|
1 | | -# Retry strategies |
| 1 | +# Retry Strategies |
2 | 2 |
|
3 | | -Retry strategies configure how the SDK responds to failures in steps. You control the |
4 | | -number of attempts, delay between retries, backoff rate, and which exceptions trigger a |
5 | | -retry. If no retry strategy is configured on a step, any exception propagates |
6 | | -immediately and fails the execution. |
| 3 | +## Retry suspends invocation |
7 | 4 |
|
8 | | -## Creating a retry strategy |
| 5 | +When a step throws an exception, the SDK uses the step's retry strategy to define the |
| 6 | +retry behaviour. When the strategy logic requires a retry, the SDK checkpoints the error |
| 7 | +and the scheduled resume time, and then ends the Lambda invocation. The backend starts a |
| 8 | +new invocation for the execution at the scheduled resume time and the SDK replays the |
| 9 | +step body. |
9 | 10 |
|
10 | | -Use `createRetryStrategy()` (TypeScript/Python) or |
11 | | -`RetryStrategies.exponentialBackoff()` (Java) to build a strategy, then pass it to |
12 | | -`StepConfig`: |
| 11 | +Retries do not consume Lambda execution time while waiting for the next retry. |
| 12 | + |
| 13 | +When a step exhausts all retry attempts, the SDK checkpoints the final error and throws |
| 14 | +it to your handler. If you configure no retry strategy on a step, any exception |
| 15 | +propagates immediately without retrying. |
| 16 | + |
| 17 | +## Configure a retry strategy |
| 18 | + |
| 19 | +A retry strategy is a function that takes the error and the current attempt number, and |
| 20 | +returns a decision. The decision is either to retry with a given delay, or to stop. You |
| 21 | +can write a retry strategy directly yourself or use the built-in helper to build a |
| 22 | +ready-made retry strategy from configuration. |
| 23 | + |
| 24 | +### RetryStrategy helper |
| 25 | + |
| 26 | +=== "TypeScript" |
| 27 | + |
| 28 | + Use `createRetryStrategy()` to build a strategy, then pass it as `retryStrategy` in |
| 29 | + `StepConfig`. |
| 30 | + |
| 31 | + ```typescript |
| 32 | + --8<-- "examples/typescript/sdk-reference/error-handling/exponential-backoff.ts" |
| 33 | + ``` |
| 34 | + |
| 35 | +=== "Python" |
| 36 | + |
| 37 | + Use `create_retry_strategy()` with a `RetryStrategyConfig`, then pass it as |
| 38 | + `retry_strategy` in `StepConfig`. |
| 39 | + |
| 40 | + ```python |
| 41 | + --8<-- "examples/python/sdk-reference/error-handling/exponential-backoff.py" |
| 42 | + ``` |
| 43 | + |
| 44 | +=== "Java" |
| 45 | + |
| 46 | + Use `RetryStrategies.exponentialBackoff()` to build a strategy, then pass it to |
| 47 | + `StepConfig.builder().retryStrategy()`. |
| 48 | + |
| 49 | + ```java |
| 50 | + --8<-- "examples/java/sdk-reference/error-handling/exponential-backoff.java" |
| 51 | + ``` |
| 52 | + |
| 53 | +#### RetryStrategyConfig signature |
| 54 | + |
| 55 | +=== "TypeScript" |
| 56 | + |
| 57 | + ```typescript |
| 58 | + --8<-- "examples/typescript/sdk-reference/error-handling/retry-strategy-config-signature.ts" |
| 59 | + ``` |
| 60 | + |
| 61 | + **Parameters:** |
| 62 | + |
| 63 | + - `maxAttempts` (optional) Total attempts including the initial attempt. Default: `3`. |
| 64 | + - `initialDelay` (optional) Delay before the first retry. Default: `{ seconds: 5 }`. |
| 65 | + - `maxDelay` (optional) Maximum delay between retries. Default: `{ minutes: 5 }`. |
| 66 | + - `backoffRate` (optional) Multiplier applied to the delay on each retry. Default: `2`. |
| 67 | + - `jitter` (optional) A `JitterStrategy` value. Default: `JitterStrategy.FULL`. |
| 68 | + - `retryableErrors` (optional) Array of strings or `RegExp` patterns matched against the |
| 69 | + error message. The SDK retries all errors when you set neither `retryableErrors` nor |
| 70 | + `retryableErrorTypes`. |
| 71 | + - `retryableErrorTypes` (optional) Array of error classes. The SDK retries only errors |
| 72 | + that are instances of these classes. When you set both filters, the SDK retries an |
| 73 | + error if it matches either (OR logic). |
| 74 | + |
| 75 | +=== "Python" |
| 76 | + |
| 77 | + ```python |
| 78 | + --8<-- "examples/python/sdk-reference/error-handling/retry-strategy-config-signature.py" |
| 79 | + ``` |
| 80 | + |
| 81 | + **Parameters:** |
| 82 | + |
| 83 | + - `max_attempts` (optional) Total attempts including the initial attempt. Default: `3`. |
| 84 | + - `initial_delay` (optional) A `Duration`. Default: `Duration.from_seconds(5)`. |
| 85 | + - `max_delay` (optional) A `Duration`. Default: `Duration.from_minutes(5)`. |
| 86 | + - `backoff_rate` (optional) Multiplier applied to the delay on each retry. Default: |
| 87 | + `2.0`. |
| 88 | + - `jitter_strategy` (optional) A `JitterStrategy` value. Default: `JitterStrategy.FULL`. |
| 89 | + - `retryable_errors` (optional) List of strings or compiled `re.Pattern` objects matched |
| 90 | + against the error message. The SDK retries all errors when you set neither |
| 91 | + `retryable_errors` nor `retryable_error_types`. |
| 92 | + - `retryable_error_types` (optional) List of exception classes. The SDK retries only |
| 93 | + exceptions that are instances of these classes. When you set both filters, the SDK |
| 94 | + retries an error if it matches either (OR logic). |
| 95 | + |
| 96 | +=== "Java" |
| 97 | + |
| 98 | + ```java |
| 99 | + --8<-- "examples/java/sdk-reference/error-handling/retry-strategy-config-signature.java" |
| 100 | + ``` |
| 101 | + |
| 102 | + **Parameters:** |
| 103 | + |
| 104 | + - `maxAttempts` Total attempts including the initial attempt. |
| 105 | + - `initialDelay` A `java.time.Duration`. Minimum 1 second. |
| 106 | + - `maxDelay` A `java.time.Duration`. Minimum 1 second. |
| 107 | + - `backoffRate` Multiplier applied to the delay on each retry. |
| 108 | + - `jitter` A `JitterStrategy` value: `FULL`, `HALF`, or `NONE`. |
| 109 | + |
| 110 | + Java does not have built-in error type filtering. Filter by error type manually inside |
| 111 | + the `RetryStrategy` lambda. See [Retrying specific errors](#retrying-specific-errors). |
| 112 | + |
| 113 | +#### JitterStrategy |
| 114 | + |
| 115 | +=== "TypeScript" |
| 116 | + |
| 117 | + ```typescript |
| 118 | + --8<-- "examples/typescript/sdk-reference/error-handling/jitter-strategy-signature.ts" |
| 119 | + ``` |
| 120 | + |
| 121 | +=== "Python" |
| 122 | + |
| 123 | + ```python |
| 124 | + --8<-- "examples/python/sdk-reference/error-handling/jitter-strategy-signature.py" |
| 125 | + ``` |
| 126 | + |
| 127 | +=== "Java" |
| 128 | + |
| 129 | + ```java |
| 130 | + --8<-- "examples/java/sdk-reference/error-handling/jitter-strategy-signature.java" |
| 131 | + ``` |
| 132 | + |
| 133 | +#### Delay calculation |
| 134 | + |
| 135 | +The SDK calculates the delay before each retry using exponential backoff with jitter: |
| 136 | + |
| 137 | +``` |
| 138 | +base_delay = min(initial_delay × backoff_rate ^ (attempt - 1), max_delay) |
| 139 | +final_delay = jitter(base_delay), minimum 1 second |
| 140 | +``` |
| 141 | + |
| 142 | +- `JitterStrategy.FULL` randomizes the delay between 0 and `base_delay`. This spreads |
| 143 | + retries across time and avoids many clients retrying simultaneously after a shared |
| 144 | + failure. |
| 145 | +- `JitterStrategy.HALF` randomizes between 50% and 100% of `base_delay`. |
| 146 | +- `JitterStrategy.NONE` uses the exact calculated delay. |
| 147 | + |
| 148 | +### Write a custom strategy |
| 149 | + |
| 150 | +You can write your own retry strategy directly. The SDK calls it with the error and the |
| 151 | +current attempt number after each failure. The attempt number is one-indexed. |
| 152 | + |
| 153 | +#### RetryStrategy signature |
13 | 154 |
|
14 | 155 | === "TypeScript" |
15 | 156 |
|
16 | 157 | ```typescript |
17 | | - --8<-- "examples/typescript/advanced/error-handling/exponential-backoff.ts" |
| 158 | + --8<-- "examples/typescript/sdk-reference/error-handling/retry-strategy-signature.ts" |
18 | 159 | ``` |
19 | 160 |
|
20 | 161 | === "Python" |
21 | 162 |
|
22 | 163 | ```python |
23 | | - --8<-- "examples/python/advanced/error-handling/exponential-backoff.py" |
| 164 | + --8<-- "examples/python/sdk-reference/error-handling/retry-strategy-signature.py" |
24 | 165 | ``` |
25 | 166 |
|
26 | 167 | === "Java" |
27 | 168 |
|
28 | 169 | ```java |
29 | | - --8<-- "examples/java/advanced/error-handling/exponential-backoff.java" |
| 170 | + --8<-- "examples/java/sdk-reference/error-handling/retry-strategy-signature.java" |
30 | 171 | ``` |
31 | 172 |
|
32 | | -## RetryStrategyConfig parameters |
| 173 | +#### Example |
| 174 | + |
| 175 | +=== "TypeScript" |
| 176 | + |
| 177 | + Return `{ shouldRetry: false }` to stop, or |
| 178 | + `{ shouldRetry: true, delay: { seconds: N } }` to retry. |
33 | 179 |
|
34 | | -**max_attempts / maxAttempts** Maximum number of attempts including the initial attempt. |
35 | | -Default: 3. |
| 180 | + ```typescript |
| 181 | + --8<-- "examples/typescript/sdk-reference/error-handling/custom-retry-strategy.ts" |
| 182 | + ``` |
36 | 183 |
|
37 | | -**initial_delay / initialDelay** Delay before the first retry. Default: 5 seconds. |
| 184 | +=== "Python" |
38 | 185 |
|
39 | | -**max_delay / maxDelay** Maximum delay between retries. Default: 5 minutes. |
| 186 | + Use `RetryDecision.retry(Duration)` or `RetryDecision.no_retry()`. |
40 | 187 |
|
41 | | -**backoff_rate / backoffRate** Multiplier for exponential backoff. Default: 2.0. |
| 188 | + ```python |
| 189 | + --8<-- "examples/python/sdk-reference/error-handling/custom-retry-strategy.py" |
| 190 | + ``` |
42 | 191 |
|
43 | | -**jitter_strategy / jitter** Jitter strategy to spread retries. Default: `FULL`. |
| 192 | +=== "Java" |
44 | 193 |
|
45 | | -**retryable_errors / retryableErrors** Error message patterns to retry (strings or |
46 | | -regex). Default: matches all errors. |
| 194 | + Use `RetryDecision.retry(Duration)` or `RetryDecision.fail()`. |
47 | 195 |
|
48 | | -**retryable_error_types / retryableErrorTypes** Exception types to retry. Default: empty |
49 | | -(retries all). |
| 196 | + ```java |
| 197 | + --8<-- "examples/java/sdk-reference/error-handling/custom-retry-strategy.java" |
| 198 | + ``` |
50 | 199 |
|
51 | 200 | ## Retry presets |
52 | 201 |
|
| 202 | +The SDK ships with preset strategies for common cases: |
| 203 | + |
53 | 204 | === "TypeScript" |
54 | 205 |
|
55 | 206 | ```typescript |
56 | | - --8<-- "examples/typescript/advanced/error-handling/retry-presets.ts" |
| 207 | + --8<-- "examples/typescript/sdk-reference/error-handling/retry-presets.ts" |
57 | 208 | ``` |
58 | 209 |
|
| 210 | + **`retryPresets.default`** 6 attempts, 5s initial delay, 60s max, 2x backoff, full |
| 211 | + jitter. |
| 212 | + |
| 213 | + **`retryPresets.noRetry`** 1 attempt, fails immediately on error. |
| 214 | + |
59 | 215 | === "Python" |
60 | 216 |
|
61 | 217 | ```python |
62 | | - --8<-- "examples/python/advanced/error-handling/retry-presets.py" |
| 218 | + --8<-- "examples/python/sdk-reference/error-handling/retry-presets.py" |
63 | 219 | ``` |
64 | 220 |
|
| 221 | + **`RetryPresets.default()`** 6 attempts, 5s initial delay, 60s max, 2x backoff, full |
| 222 | + jitter. |
| 223 | + |
| 224 | + **`RetryPresets.none()`** 1 attempt, fails immediately on error. |
| 225 | + |
| 226 | + **`RetryPresets.transient()`** 3 attempts, 2x backoff, half jitter. |
| 227 | + |
| 228 | + **`RetryPresets.resource_availability()`** 5 attempts, 5s initial delay, 5 min max, 2x |
| 229 | + backoff. |
| 230 | + |
| 231 | + **`RetryPresets.critical()`** 10 attempts, 1s initial delay, 60s max, 1.5x backoff, no |
| 232 | + jitter. |
| 233 | + |
65 | 234 | === "Java" |
66 | 235 |
|
67 | 236 | ```java |
68 | | - --8<-- "examples/java/advanced/error-handling/retry-presets.java" |
| 237 | + --8<-- "examples/java/sdk-reference/error-handling/retry-presets.java" |
69 | 238 | ``` |
70 | 239 |
|
71 | | -## Retrying specific exceptions |
| 240 | + **`RetryStrategies.Presets.DEFAULT`** 6 attempts, 5s initial delay, 60s max, 2x backoff, |
| 241 | + full jitter. |
| 242 | + |
| 243 | + **`RetryStrategies.Presets.NO_RETRY`** Fails immediately on first error. |
| 244 | + |
| 245 | +## Retry only specific errors |
| 246 | + |
| 247 | +You can retry only certain error types and fail immediately on others. |
72 | 248 |
|
73 | 249 | === "TypeScript" |
74 | 250 |
|
| 251 | + Use `retryableErrorTypes` to specify which error classes to retry. |
| 252 | + |
75 | 253 | ```typescript |
76 | | - --8<-- "examples/typescript/sdk-reference/error-handling/unreliable-operation.ts" |
| 254 | + --8<-- "examples/typescript/sdk-reference/error-handling/retry-specific-errors.ts" |
77 | 255 | ``` |
78 | 256 |
|
79 | 257 | === "Python" |
80 | 258 |
|
| 259 | + Use `retryable_error_types` to specify which exception classes to retry. |
| 260 | + |
81 | 261 | ```python |
82 | | - --8<-- "examples/python/sdk-reference/error-handling/unreliable-operation.py" |
| 262 | + --8<-- "examples/python/sdk-reference/error-handling/retry-specific-errors.py" |
83 | 263 | ``` |
84 | 264 |
|
85 | 265 | === "Java" |
86 | 266 |
|
| 267 | + `RetryStrategy` is a functional interface. Check the error type in the lambda and return |
| 268 | + `RetryDecision.fail()` for errors you do not want to retry. |
| 269 | + |
87 | 270 | ```java |
88 | | - --8<-- "examples/java/sdk-reference/error-handling/unreliable-operation.java" |
| 271 | + --8<-- "examples/java/sdk-reference/error-handling/retry-specific-errors.java" |
89 | 272 | ``` |
90 | 273 |
|
91 | 274 | ## See also |
|
0 commit comments