From 2d38d486bec0cbbca48d424e59ef52e91f3e9587 Mon Sep 17 00:00:00 2001 From: Miriad Date: Tue, 3 Mar 2026 14:32:29 +0000 Subject: [PATCH] fix: use after() instead of fire-and-forget in video webhook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Vercel serverless, functions terminate after the response is sent. The fire-and-forget pattern (promise.catch() without await) caused the video pipeline to silently die after setting audio_gen status. next/server's after() keeps the function alive for background work, allowing the full pipeline (ElevenLabs TTS → GCS → Remotion → GCS) to complete after returning 200 to Sanity. --- app/api/webhooks/sanity-content/route.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/app/api/webhooks/sanity-content/route.ts b/app/api/webhooks/sanity-content/route.ts index 7f276e33..13f937ce 100644 --- a/app/api/webhooks/sanity-content/route.ts +++ b/app/api/webhooks/sanity-content/route.ts @@ -1,4 +1,4 @@ -import { NextResponse } from 'next/server'; +import { NextResponse, after } from 'next/server'; import { isValidSignature, SIGNATURE_HEADER_NAME } from '@sanity/webhook'; import { processVideoProduction } from '@/lib/services/video-pipeline'; @@ -82,10 +82,16 @@ export async function POST(request: Request) { ); } - // Fire and forget — trigger pipeline in background, return 200 immediately + // Use after() to run the pipeline after the response is sent. + // On Vercel, serverless functions terminate after the response — fire-and-forget + // (promise.catch()) silently dies. after() keeps the function alive for background work. console.log(`[WEBHOOK] Triggering video production for document: ${body._id}`); - processVideoProduction(body._id).catch((error) => { - console.log(`[WEBHOOK] Background processing error for ${body._id}:`, error); + after(async () => { + try { + await processVideoProduction(body._id); + } catch (error) { + console.error(`[WEBHOOK] Background processing error for ${body._id}:`, error); + } }); return NextResponse.json({ triggered: true }, { status: 200 });