Skip to content

Commit eaf7392

Browse files
committed
fix(billing): release reserved slot on execute-route 503 and setup throw
After preprocessExecution reserves a billing concurrency slot, the streaming path could exit without releasing it: the 503 return when initializeExecutionStreamMeta fails, and any throw during stream setup (caught by the outer handler, which only returned 500). Both left the slot held until TTL, wrongly throttling unrelated runs. Release on the 503 path and in the outer catch (executionId hoisted so the catch can see it; release is idempotent and a no-op when no slot was reserved).
1 parent 7927336 commit eaf7392

1 file changed

Lines changed: 9 additions & 2 deletions

File tree

  • apps/sim/app/api/workflows/[id]/execute

apps/sim/app/api/workflows/[id]/execute/route.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,10 @@ async function handleExecutePost(
378378
}
379379
const callChain = buildNextCallChain(incomingCallChain, workflowId)
380380

381+
// Hoisted so the outer catch can release a reserved billing slot when a throw
382+
// after preprocessExecution exits before the stream takes over its release.
383+
let executionId = ''
384+
381385
try {
382386
const auth = await checkHybridAuth(req, { requireWorkflowId: false })
383387
const isMcpBridgeRequest =
@@ -637,8 +641,7 @@ async function handleExecutePost(
637641
)
638642
}
639643

640-
const executionId =
641-
isClientSession && requestedExecutionId ? requestedExecutionId : generateId()
644+
executionId = isClientSession && requestedExecutionId ? requestedExecutionId : generateId()
642645
reqLogger = reqLogger.withMetadata({ userId, executionId })
643646

644647
reqLogger.info('Starting server-side execution', {
@@ -1166,6 +1169,7 @@ async function handleExecutePost(
11661169
})
11671170
if (!metaInitialized) {
11681171
timeoutController.cleanup()
1172+
await releaseExecutionSlot(executionId)
11691173
return NextResponse.json(
11701174
{ error: 'Run buffer temporarily unavailable' },
11711175
{ status: 503, headers: { 'X-Execution-Id': executionId } }
@@ -1724,6 +1728,9 @@ async function handleExecutePost(
17241728
})
17251729
} catch (error: any) {
17261730
reqLogger.error('Failed to start workflow execution:', error)
1731+
// Release a reserved billing slot if a throw exited before the stream took
1732+
// over its release (idempotent; no-op when never reserved).
1733+
if (executionId) await releaseExecutionSlot(executionId)
17271734
return NextResponse.json(
17281735
{ error: error.message || 'Failed to start workflow execution' },
17291736
{ status: 500 }

0 commit comments

Comments
 (0)