@@ -12,10 +12,20 @@ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
1212
1313// Shared order processing logic - Hardened for Production
1414const processOrderCreation = async ( userId : string , sessionId : string , paymentMethod : string ) => {
15+ const createdKey = `order-created:${ sessionId } ` ;
16+ // Atomically set processed flag / acquire lock to prevent duplicate creation
17+ const lockAcquired = await redis . set ( createdKey , "true" , "EX" , 86400 , "NX" ) ;
18+ if ( ! lockAcquired ) {
19+ console . log ( `[Order] Order for session ${ sessionId } is already processed or being processed.` ) ;
20+ return ;
21+ }
22+
1523 const sessionKey = `payment-session:${ sessionId } ` ;
1624 const sessionData = await redis . get ( sessionKey ) ;
1725
1826 if ( ! sessionData ) {
27+ // Release lock so it can be retried later
28+ await redis . del ( createdKey ) ;
1929 throw new Error ( `Critical: Payment session ${ sessionId } not found or expired.` ) ;
2030 }
2131
@@ -290,7 +300,33 @@ export const verifyPaymentSession = async (req: any, res: Response, next: NextFu
290300 const sessionId = req . query . sessionId as string ;
291301 const sessionData = await redis . get ( `payment-session:${ sessionId } ` ) ;
292302 if ( ! sessionData ) return res . status ( 404 ) . json ( { message : "Session expired" } ) ;
293- return res . status ( 200 ) . json ( { success : true , session : JSON . parse ( sessionData ) } ) ;
303+
304+ const session = JSON . parse ( sessionData ) ;
305+
306+ // Self-heal: Check if order has already been created for this session
307+ const createdKey = `order-created:${ sessionId } ` ;
308+ const isCreated = await redis . get ( createdKey ) ;
309+
310+ if ( ! isCreated ) {
311+ console . log ( `[Order] Order not marked as created for session ${ sessionId } . Checking Stripe...` ) ;
312+ try {
313+ // Search for Stripe PaymentIntent matching this sessionId
314+ const searchResults = await stripe . paymentIntents . search ( {
315+ query : `metadata['sessionId']:'${ sessionId } '` ,
316+ } ) ;
317+
318+ const paymentIntent = searchResults . data [ 0 ] ;
319+ if ( paymentIntent && paymentIntent . status === "succeeded" ) {
320+ console . log ( `[Order] Found succeeded Stripe PaymentIntent ${ paymentIntent . id } for session ${ sessionId } . Self-healing order creation...` ) ;
321+ const userId = paymentIntent . metadata . userId || session . userId ;
322+ await processOrderCreation ( userId , sessionId , "Stripe" ) ;
323+ }
324+ } catch ( stripeError ) {
325+ console . error ( "[Order] Stripe session self-healing check failed:" , stripeError ) ;
326+ }
327+ }
328+
329+ return res . status ( 200 ) . json ( { success : true , session } ) ;
294330 } catch ( error ) {
295331 return next ( error )
296332 }
0 commit comments