|
1 | 1 | import ms from "ms"; |
2 | | -import { NextRequest, NextResponse } from "next/server"; |
| 2 | +import { NextRequest, NextResponse, after } from "next/server"; |
3 | 3 | import { getCorsHeaders } from "@/lib/networking/getCorsHeaders"; |
4 | 4 | import { validateCreateSandboxBody } from "@/lib/sandbox/validateCreateSandboxBody"; |
5 | 5 | import { selectSessions } from "@/lib/supabase/sessions/selectSessions"; |
@@ -145,11 +145,17 @@ export async function createSandboxHandler(request: NextRequest): Promise<NextRe |
145 | 145 | } |
146 | 146 |
|
147 | 147 | // Register the new sandbox with the lifecycle workflow so it gets |
148 | | - // auto-paused after SANDBOX_INACTIVITY_TIMEOUT_MS of idle. Fire-and- |
149 | | - // forget — failure to start the workflow doesn't fail the request, |
150 | | - // and a future status read will reclaim a stale lease if the |
151 | | - // workflow never picked up. |
152 | | - kickSandboxLifecycleWorkflow({ sessionId: sessionRow.id, reason: "sandbox-created" }); |
| 148 | + // auto-paused after SANDBOX_INACTIVITY_TIMEOUT_MS of idle. The |
| 149 | + // kick chain (selectSessions → claim lease → start workflow) is |
| 150 | + // registered with `after()` so the serverless platform keeps the |
| 151 | + // function alive past the response until the chain completes — |
| 152 | + // without that, the chain dies on function teardown and the |
| 153 | + // workflow never starts. Failures are logged and never surfaced. |
| 154 | + kickSandboxLifecycleWorkflow({ |
| 155 | + sessionId: sessionRow.id, |
| 156 | + reason: "sandbox-created", |
| 157 | + scheduleBackgroundWork: task => after(() => task), |
| 158 | + }); |
153 | 159 | } |
154 | 160 |
|
155 | 161 | return NextResponse.json( |
|
0 commit comments