Skip to content

Commit 78695dc

Browse files
authored
Merge pull request #89 from nibble-4bits/feature/retry-override-cli-option
Feature/retry override cli option
2 parents 6e1a55b + ac8b24a commit 78695dc

File tree

6 files changed

+85
-4
lines changed

6 files changed

+85
-4
lines changed

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ This package lets you run AWS Step Functions state machines completely locally,
4141
- [Overriding Task and Wait states](#overriding-task-and-wait-states)
4242
- [Task state override](#task-state-override)
4343
- [Wait state override](#wait-state-override)
44+
- [Retry field pause override](#retry-field-pause-override)
4445
- [Passing a custom Context Object](#passing-a-custom-context-object)
4546
- [Disabling ASL validations](#disabling-asl-validations)
4647
- [Exit codes](#exit-codes)
@@ -362,6 +363,54 @@ local-sfn \
362363

363364
This command would execute the state machine, and override `Wait` states `WaitResponse` and `PauseUntilSignal` to pause the execution for 1500 and 250 milliseconds, respectively. The `Delay` state wouldn't be paused at all, since the override value is set to 0.
364365

366+
#### Retry field pause override
367+
368+
To override the duration of the pause in the `Retry` field of a state, pass the `-r, --override-retry` option. This option takes as value the name of the state whose `Retry` field you want to override, and a number that represents the amount in milliseconds that you want to pause the execution for before retrying the state. The state name and the milliseconds amount must be separated by a colon `:`.
369+
370+
For example, suppose the state machine definition contains a state called `TaskToRetry` that is defined as follows:
371+
372+
```json
373+
{
374+
"Type": "Task",
375+
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:HelloWorld",
376+
"Retry": [
377+
{ "ErrorEquals": ["States.Timeout", "SyntaxError"] },
378+
{ "ErrorEquals": ["RangeError"] },
379+
{ "ErrorEquals": ["States.ALL"] }
380+
],
381+
"End": true
382+
}
383+
```
384+
385+
Then, the following command is run:
386+
387+
```sh
388+
local-sfn -f state-machine.json -r TaskToRetry:100 '{ "num1": 1, "num2": 2 }'
389+
```
390+
391+
This command would execute the state machine, and if the `TaskToRetry` state fails, the execution would be paused for 100 milliseconds before retrying the state again, disregarding the `IntervalSeconds`, `BackoffRate`, `MaxDelaySeconds`, and `JitterStrategy` fields that could've been specified in any of the `Retry` field retriers.
392+
393+
Alternatively, you can also pass a list of comma-separated numbers as value, to override the duration of specific retriers, for instance:
394+
395+
```sh
396+
local-sfn -f state-machine.json -r TaskToRetry:100,-1,20 '{ "num1": 1, "num2": 2 }'
397+
```
398+
399+
The above command would pause the execution for 100 milliseconds if the state error is matched by the first retrier and it would pause for 20 milliseconds if the error matches the third retrier. Note that a -1 was passed for the second retrier. This means that the pause duration of the second retrier will not be overridden, instead, it will be calculated as usually with the `IntervalSeconds` and the other retrier fields, or use the default values if said fields are not specified.
400+
401+
Furthermore, you can pass this option multiple times, to override the `Retry` fields in multiple states. For example:
402+
403+
```sh
404+
local-sfn \
405+
-f state-machine.json \
406+
-r SendRequest:1500 \
407+
-r ProcessData:250 \
408+
-r MapResponses:0 \
409+
'{ "num1": 1, "num2": 2 }'
410+
```
411+
412+
This command would execute the state machine, and override the duration of the retry pause in states `SendRequest` and `ProcessData` to pause the execution for 1500 and 250 milliseconds, respectively. The retry in the `MapResponses` state wouldn't be paused at all, since the override value is set to 0.
413+
365414
### Passing a custom Context Object
366415

367416
If the JSONPaths in your definition reference the Context Object, you can provide a mock Context Object by passing either the `--context` or the `--context-file` option. For example, given the following definition:

__tests__/cli/CLI.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ describe('CLI', () => {
3434

3535
await expect(program.parseAsync([], { from: 'user' })).rejects.toThrow();
3636
expect(helpStr).toBe(
37-
'Usage: local-sfn [options] [inputs...]\n\nExecute an Amazon States Language state machine with the given inputs.\nThe result of each execution will be output in a new line and in the same order\nas its corresponding input.\n\nArguments:\n inputs Input data for the state machine, can be any\n valid JSON value. Each input represents a\n state machine execution.\n \n When reading from the standard input, if the\n first line can be parsed as a single JSON\n value, then each line will be considered as an\n input. Otherwise, the entire standard input\n will be considered as a single JSON input.\n\nOptions:\n -V, --version Print the version number and exit.\n -d, --definition <definition> A JSON definition of a state machine.\n -f, --definition-file <path> Path to a file containing a JSON state machine\n definition.\n -t, --override-task <mapping> Override a Task state to run an executable\n file or script, instead of calling the service\n specified in the \'Resource\' field of the state\n definition. The mapping value has to be\n provided in the format\n [TaskStateToOverride]:[path/to/override/script].\n The override script will be passed the input\n of the Task state as first argument, which can\n then be used to compute the task result. The\n script must print the task result as a JSON\n value to the standard output.\n -w, --override-wait <mapping> Override a Wait state to pause for the\n specified amount of milliseconds, instead of\n pausing for the duration specified in the\n state definition. The mapping value has to be\n provided in the format\n [WaitStateToOverride]:[number].\n --context <json> A JSON object that will be passed to each\n execution as the context object.\n --context-file <path> Path to a file containing a JSON object that\n will be passed to each execution as the\n context object.\n --no-jsonpath-validation Disable validation of JSONPath strings in the\n state machine definition.\n --no-arn-validation Disable validation of ARNs in the state\n machine definition.\n --no-validation Disable validation of the state machine\n definition entirely. Use this option at your\n own risk, there are no guarantees when passing\n an invalid or non-standard definition to the\n state machine. Running it might result in\n undefined/unsupported behavior.\n -h, --help Print help for command and exit.\n\nExit codes:\n 0 All executions ran successfully.\n 1 An error occurred before the state machine could be executed.\n 2 At least one execution had an error.\n\nExample calls:\n $ local-sfn -f state-machine.json \'{ "num1": 2, "num2": 2 }\'\n $ local-sfn -f state-machine.json -t SendRequest:./override.sh -w WaitResponse:2000 \'{ "num1": 2, "num2": 2 }\'\n $ cat inputs.txt | local-sfn -f state-machine.json\n'
37+
'Usage: local-sfn [options] [inputs...]\n\nExecute an Amazon States Language state machine with the given inputs.\nThe result of each execution will be printed in a new line and in the same\norder as its corresponding input.\n\nArguments:\n inputs Input data for the state machine, can be any\n valid JSON value. Each input represents a\n state machine execution.\n \n When reading from the standard input, if the\n first line can be parsed as a single JSON\n value, then each line will be considered as\n an input. Otherwise, the entire standard\n input will be considered as a single JSON\n input.\n\nOptions:\n -V, --version Print the version number and exit.\n -d, --definition <definition> A JSON definition of a state machine.\n -f, --definition-file <path> Path to a file containing a JSON state\n machine definition.\n -t, --override-task <mapping> Override a Task state to run an executable\n file or script, instead of calling the\n service specified in the \'Resource\' field of\n the state definition. The mapping value has\n to be provided in the format\n [TaskStateToOverride]:[path/to/override/script].\n The override script will be passed the input\n of the Task state as first argument, which\n can then be used to compute the task result.\n The script must print the task result as a\n JSON value to the standard output.\n -w, --override-wait <mapping> Override a Wait state to pause for the\n specified amount of milliseconds, instead of\n pausing for the duration specified in the\n state definition. The mapping value has to be\n provided in the format\n [WaitStateToOverride]:[number].\n -r, --override-retry <mapping> Override a \'Retry\' field to pause for the\n specified amount of milliseconds, instead of\n pausing for the duration specified by the\n retry policy. The mapping value has to be\n provided in the format\n [NameOfStateWithRetryField]:[number].\n --context <json> A JSON object that will be passed to each\n execution as the context object.\n --context-file <path> Path to a file containing a JSON object that\n will be passed to each execution as the\n context object.\n --no-jsonpath-validation Disable validation of JSONPath strings in the\n state machine definition.\n --no-arn-validation Disable validation of ARNs in the state\n machine definition.\n --no-validation Disable validation of the state machine\n definition entirely. Use this option at your\n own risk, there are no guarantees when\n passing an invalid or non-standard definition\n to the state machine. Running it might result\n in undefined/unsupported behavior.\n -h, --help Print help for command and exit.\n\nExit codes:\n 0 All executions ran successfully.\n 1 An error occurred before the state machine could be executed.\n 2 At least one execution had an error.\n\nExample calls:\n $ local-sfn -f state-machine.json \'{ "num1": 2, "num2": 2 }\'\n $ local-sfn -f state-machine.json -t SendRequest:./override.sh -w WaitResponse:2000 \'{ "num1": 2, "num2": 2 }\'\n $ cat inputs.txt | local-sfn -f state-machine.json\n'
3838
);
3939
});
4040
});

src/cli/ArgumentParsers.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import type { Command } from 'commander';
22
import type { StateMachineDefinition } from '../typings/StateMachineDefinition';
3-
import type { TaskStateResourceLocalHandler, WaitStateTimeOverride } from '../typings/StateMachineImplementation';
3+
import type {
4+
TaskStateResourceLocalHandler,
5+
WaitStateTimeOverride,
6+
RetryIntervalOverrides,
7+
} from '../typings/StateMachineImplementation';
48
import type { JSONValue } from '../typings/JSONValue';
59
import type { Context } from '../typings/Context';
610
import { readFileSync } from 'fs';
@@ -85,6 +89,20 @@ function parseOverrideWaitOption(value: string, previous: WaitStateTimeOverride
8589
return previous;
8690
}
8791

92+
function parseOverrideRetryOption(value: string, previous: RetryIntervalOverrides = {}): RetryIntervalOverrides {
93+
const [stateName, duration] = value.split(':');
94+
95+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
96+
// @ts-ignore
97+
if (!isNaN(duration)) {
98+
previous[stateName] = Number(duration);
99+
} else {
100+
previous[stateName] = duration.split(',').map(Number);
101+
}
102+
103+
return previous;
104+
}
105+
88106
function parseContextOption(command: Command, context: string) {
89107
const jsonOrError = tryJSONParse<Context>(context);
90108

@@ -137,6 +155,7 @@ export {
137155
parseDefinitionFileOption,
138156
parseOverrideTaskOption,
139157
parseOverrideWaitOption,
158+
parseOverrideRetryOption,
140159
parseInputArguments,
141160
parseContextOption,
142161
parseContextFileOption,

src/cli/CLI.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
parseInputArguments,
1111
parseOverrideTaskOption,
1212
parseOverrideWaitOption,
13+
parseOverrideRetryOption,
1314
parseContextOption,
1415
parseContextFileOption,
1516
} from './ArgumentParsers';
@@ -23,7 +24,7 @@ function makeProgram() {
2324
.name('local-sfn')
2425
.description(
2526
`Execute an Amazon States Language state machine with the given inputs.
26-
The result of each execution will be output in a new line and in the same order as its corresponding input.`
27+
The result of each execution will be printed in a new line and in the same order as its corresponding input.`
2728
)
2829
.helpOption('-h, --help', 'Print help for command and exit.')
2930
.configureHelp({ helpWidth: 80 })
@@ -63,6 +64,12 @@ Example calls:
6364
'Override a Wait state to pause for the specified amount of milliseconds, instead of pausing for the duration specified in the state definition. The mapping value has to be provided in the format [WaitStateToOverride]:[number].'
6465
).argParser(parseOverrideWaitOption)
6566
)
67+
.addOption(
68+
new Option(
69+
'-r, --override-retry <mapping>',
70+
"Override a 'Retry' field to pause for the specified amount of milliseconds, instead of pausing for the duration specified by the retry policy. The mapping value has to be provided in the format [NameOfStateWithRetryField]:[number]."
71+
).argParser(parseOverrideRetryOption)
72+
)
6673
.addOption(
6774
new Option(
6875
'--context <json>',

src/cli/CommandHandler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ async function commandAction(inputs: JSONValue[], options: ParsedCommandOptions,
2323
overrides: {
2424
taskResourceLocalHandlers: options.overrideTask,
2525
waitTimeOverrides: options.overrideWait,
26+
retryIntervalOverrides: options.overrideRetry,
2627
},
2728
context: options.context ?? options.contextFile,
2829
});

src/typings/CLI.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import type { Context } from './Context';
22
import type { StateMachineDefinition } from './StateMachineDefinition';
3-
import type { TaskStateResourceLocalHandler, WaitStateTimeOverride } from './StateMachineImplementation';
3+
import type {
4+
TaskStateResourceLocalHandler,
5+
WaitStateTimeOverride,
6+
RetryIntervalOverrides,
7+
} from './StateMachineImplementation';
48

59
export type ParsedCommandOptions = {
610
definition: StateMachineDefinition;
711
definitionFile: StateMachineDefinition;
812
overrideTask: TaskStateResourceLocalHandler;
913
overrideWait: WaitStateTimeOverride;
14+
overrideRetry: RetryIntervalOverrides;
1015
context: Context;
1116
contextFile: Context;
1217
jsonpathValidation: boolean;

0 commit comments

Comments
 (0)