@@ -719,4 +719,49 @@ describe('e2e', () => {
719719 expect ( stepCompletedEvents ) . toHaveLength ( 1 ) ;
720720 }
721721 ) ;
722+
723+ test (
724+ 'processExitResilienceWorkflow - step self-terminates on first attempt' ,
725+ { timeout : 60_000 } ,
726+ async ( ) => {
727+ // This test verifies that the workflow system is resilient to fatal process crashes
728+ // The step will call process.exit() on the first attempt, simulating an unhandled
729+ // fatal error, but the system should recover and retry on a new process
730+ const run = await triggerWorkflow ( 'processExitResilienceWorkflow' , [ ] ) ;
731+ const returnValue = await getWorkflowReturnValue ( run . runId ) ;
732+
733+ // The workflow should complete successfully after the process crash
734+ expect ( returnValue ) . toMatchObject ( {
735+ attempt : 2 ,
736+ status : 'recovered' ,
737+ } ) ;
738+
739+ // Verify the run data shows successful completion
740+ const { json : runData } = await cliInspectJson (
741+ `runs ${ run . runId } --withData`
742+ ) ;
743+ expect ( runData ) . toMatchObject ( {
744+ runId : run . runId ,
745+ status : 'completed' ,
746+ output : { attempt : 2 , status : 'recovered' } ,
747+ } ) ;
748+
749+ // Query steps to verify the step was retried
750+ const { json : stepsData } = await cliInspectJson (
751+ `steps --runId ${ run . runId } --withData`
752+ ) ;
753+ expect ( stepsData ) . toBeDefined ( ) ;
754+ expect ( Array . isArray ( stepsData ) ) . toBe ( true ) ;
755+ expect ( stepsData . length ) . toBeGreaterThan ( 0 ) ;
756+
757+ // Find the stepThatExitsOnFirstAttempt step
758+ const exitStep = stepsData . find ( ( s : any ) =>
759+ s . stepName . includes ( 'stepThatExitsOnFirstAttempt' )
760+ ) ;
761+ expect ( exitStep ) . toBeDefined ( ) ;
762+ expect ( exitStep . status ) . toBe ( 'completed' ) ;
763+ expect ( exitStep . attempt ) . toBe ( 2 ) ;
764+ expect ( exitStep . output ) . toEqual ( [ { attempt : 2 , status : 'recovered' } ] ) ;
765+ }
766+ ) ;
722767} ) ;
0 commit comments