@@ -34,6 +34,11 @@ const {
3434 mockReleaseExecutionIdClaim,
3535 mockReleaseExecutionSlot,
3636 mockRequireBillingAttributionHeader,
37+ mockShouldExecuteInline,
38+ mockStartJob,
39+ mockCompleteJob,
40+ mockMarkJobFailed,
41+ mockExecuteWorkflowJob,
3742 mockValidatePublicApiAllowed,
3843} = vi . hoisted ( ( ) => ( {
3944 mockAssertBillingAttributionSnapshot : vi . fn ( ( value : unknown ) => {
@@ -52,6 +57,11 @@ const {
5257 mockReleaseExecutionIdClaim : vi . fn ( ) ,
5358 mockReleaseExecutionSlot : vi . fn ( ) ,
5459 mockRequireBillingAttributionHeader : vi . fn ( ) ,
60+ mockShouldExecuteInline : vi . fn ( ( ) => false ) ,
61+ mockStartJob : vi . fn ( ) ,
62+ mockCompleteJob : vi . fn ( ) ,
63+ mockMarkJobFailed : vi . fn ( ) ,
64+ mockExecuteWorkflowJob : vi . fn ( ) ,
5565 mockValidatePublicApiAllowed : vi . fn ( ) ,
5666} ) )
5767
@@ -114,11 +124,11 @@ vi.mock('@/lib/execution/payloads/store', () => ({
114124vi . mock ( '@/lib/core/async-jobs' , ( ) => ( {
115125 getJobQueue : vi . fn ( ) . mockResolvedValue ( {
116126 enqueue : mockEnqueue ,
117- startJob : vi . fn ( ) ,
118- completeJob : vi . fn ( ) ,
119- markJobFailed : vi . fn ( ) ,
127+ startJob : mockStartJob ,
128+ completeJob : mockCompleteJob ,
129+ markJobFailed : mockMarkJobFailed ,
120130 } ) ,
121- shouldExecuteInline : vi . fn ( ) . mockReturnValue ( false ) ,
131+ shouldExecuteInline : mockShouldExecuteInline ,
122132} ) )
123133
124134vi . mock ( '@/lib/core/utils/urls' , ( ) => ( {
@@ -136,7 +146,7 @@ vi.mock('@/lib/execution/call-chain', () => ({
136146vi . mock ( '@/lib/logs/execution/logging-session' , ( ) => loggingSessionMock )
137147
138148vi . mock ( '@/background/workflow-execution' , ( ) => ( {
139- executeWorkflowJob : vi . fn ( ) ,
149+ executeWorkflowJob : mockExecuteWorkflowJob ,
140150} ) )
141151
142152vi . mock ( '@sim/utils/id' , ( ) => ( {
@@ -288,6 +298,8 @@ describe('workflow execute async route', () => {
288298 beforeEach ( ( ) => {
289299 vi . clearAllMocks ( )
290300 resetDbChainMock ( )
301+ mockShouldExecuteInline . mockReturnValue ( false )
302+ mockExecuteWorkflowJob . mockResolvedValue ( { success : true } )
291303 mockGenerateId . mockReset ( ) . mockReturnValue ( 'execution-123' )
292304 mockClaimExecutionId . mockImplementation ( async ( executionId : string ) => ( {
293305 key : `workflow-execution-id:${ executionId } ` ,
@@ -392,6 +404,36 @@ describe('workflow execute async route', () => {
392404 )
393405 } )
394406
407+ it ( 'retains the admission ticket until database-backed async execution finishes' , async ( ) => {
408+ mockShouldExecuteInline . mockReturnValue ( true )
409+ let resolveInlineExecution ! : ( ) => void
410+ const inlineExecution = new Promise < void > ( ( resolve ) => {
411+ resolveInlineExecution = resolve
412+ } )
413+ mockExecuteWorkflowJob . mockReturnValueOnce ( inlineExecution )
414+
415+ const response = await POST (
416+ createMockRequest (
417+ 'POST' ,
418+ { input : { hello : 'world' } } ,
419+ {
420+ 'Content-Type' : 'application/json' ,
421+ 'X-Execution-Mode' : 'async' ,
422+ }
423+ ) ,
424+ { params : Promise . resolve ( { id : 'workflow-1' } ) }
425+ )
426+
427+ expect ( response . status ) . toBe ( 202 )
428+ expect ( getAdmissionGateStatus ( ) . inflight ) . toBe ( 1 )
429+
430+ resolveInlineExecution ( )
431+ await vi . waitFor ( ( ) => {
432+ expect ( getAdmissionGateStatus ( ) . inflight ) . toBe ( 0 )
433+ } )
434+ expect ( mockCompleteJob ) . toHaveBeenCalledWith ( 'job-123' , expect . anything ( ) )
435+ } )
436+
395437 it ( 'applies admission backpressure to session-backed async executions' , async ( ) => {
396438 hybridAuthMockFns . mockHasExternalApiCredentials . mockReturnValue ( false )
397439 const heldTickets = Array . from ( { length : getAdmissionGateStatus ( ) . maxInflight } , ( ) =>
0 commit comments