diff --git a/lib/stepfunctions.js b/lib/stepfunctions.js index b389755..2166450 100644 --- a/lib/stepfunctions.js +++ b/lib/stepfunctions.js @@ -148,6 +148,7 @@ class StepFunction extends EventEmitter { if (state.Parameters) { let newInput = {}; const context = this.getContext(); + input = context.Execution.Input; Object.keys(state.Parameters) .filter((parameter) => parameter !== 'comment') .map((parameter) => { @@ -922,10 +923,11 @@ class StepFunction extends EventEmitter { */ createContext(state, task, input, index = null, retries) { const id = +new Date(); + this._lastInputBeforeRetry = retries ? this._lastInputBeforeRetry : input; this._current.context = { Execution: { Id: `arn:aws:states:ap-southeast-1:123456789012:execution:stateMachineName:${id}`, - Input: input, + Input: this._lastInputBeforeRetry, Name: +new Date(), RoleArn: 'arn:aws:iam::123456789012:role...', StartTime: new Date().toISOString(), @@ -936,8 +938,7 @@ class StepFunction extends EventEmitter { RetryCount: retries || this._current.retries || 0, }, StateMachine: { - Id: - 'arn:aws:states:ap-southeast-1:123456789012:stateMachine:stateMachineName', + Id: 'arn:aws:states:ap-southeast-1:123456789012:stateMachine:stateMachineName', Name: this.Name, }, Task: { diff --git a/test/stepfunctions.test.js b/test/stepfunctions.test.js index dbab5b0..87b71b3 100644 --- a/test/stepfunctions.test.js +++ b/test/stepfunctions.test.js @@ -725,6 +725,38 @@ describe('Stepfunctions', () => { ); }, 8000); + it('can retry failing tasks and maintain the same transformed input', async () => { + const sm = new Sfn({ + StateMachine: require('./steps/retry-transform-input.json'), + }); + const args = { bar: 'baz' }; + const firstFn = jest.fn((input) => { + const { retries, foo } = input; + expect(foo).toEqual(args); + if (retries === 3) { + return input; + } + class CustomError extends Error { + // empty + } + throw new CustomError('something happened'); + }); + const errorFn = jest.fn((input) => input); + const lastFn = jest.fn((input) => { + return input; + }); + sm.bindTaskResource('First', firstFn); + sm.bindTaskResource('All', errorFn); + sm.bindTaskResource('Last', lastFn); + await sm.startExecution(args); + expect(firstFn).toHaveBeenCalled(); + expect(errorFn).not.toHaveBeenCalled(); + expect(lastFn).toHaveBeenCalled(); + expect(sm.getExecutionResult()).toEqual( + expect.objectContaining({ retries: 3, foo: args }), + ); + }, 8000); + it('can retry failing tasks and finally catch', async () => { const sm = new Sfn({ StateMachine: require('./steps/retry.json') }); const firstFn = jest.fn(() => { diff --git a/test/steps/retry-transform-input.json b/test/steps/retry-transform-input.json new file mode 100644 index 0000000..890573f --- /dev/null +++ b/test/steps/retry-transform-input.json @@ -0,0 +1,39 @@ +{ + "StartAt": "First", + "States": { + "First": { + "Type": "Task", + "Resource": "arn:aws:lambda:ap-southeast-1:123456789012:function:test", + "Parameters": { + "foo.$": "$", + "retries.$": "$$.State.RetryCount" + }, + "Retry": [ + { + "ErrorEquals": ["CustomError"], + "IntervalSeconds": 1, + "BackoffRate": 1, + "MaxAttempts": 3 + } + ], + "Catch": [ + { + "ErrorEquals": ["CustomError"], + "ResultPath": "$.error", + "Next": "All" + } + ], + "Next": "Last" + }, + "All": { + "Type": "Task", + "Resource": "arn:aws:lambda:ap-southeast-1:123456789012:function:test", + "Next": "Last" + }, + "Last": { + "Type": "Task", + "Resource": "arn:aws:lambda:ap-southeast-1:123456789012:function:test", + "End": true + } + } +}