Skip to content

Commit 68ebea2

Browse files
committed
docs: error-handling
- Rewrite errors.md: clear narrative flow, step errors retry, outside-step errors fail immediately, retries exhausted, replay re-throws - Add Mermaid exception hierarchy diagrams for all three SDKs - Fix Python exception hierarchy to include UserlandError - Rewrite retries.md: helper and custom strategy sections, Parameters under helper, JitterStrategy section, delay calculation under helper - Fix serdes error behavior: Java and Python return FAILED, TypeScript retries via unhandled SerdesFailedError - Move all error-handling examples to sdk-reference/error-handling - Fix passive voice, hyphen separators, present-participle headings throughout Closes #42, closes #66, closes #48, closes #6
1 parent e9aacd3 commit 68ebea2

132 files changed

Lines changed: 1171 additions & 941 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/sdk-reference/error-handling/errors.md

Lines changed: 141 additions & 738 deletions
Large diffs are not rendered by default.

docs/sdk-reference/error-handling/retries.md

Lines changed: 213 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,274 @@
1-
# Retry strategies
1+
# Retry Strategies
22

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
74

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.
910

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
13154

14155
=== "TypeScript"
15156

16157
```typescript
17-
--8<-- "examples/typescript/advanced/error-handling/exponential-backoff.ts"
158+
--8<-- "examples/typescript/sdk-reference/error-handling/retry-strategy-signature.ts"
18159
```
19160

20161
=== "Python"
21162

22163
```python
23-
--8<-- "examples/python/advanced/error-handling/exponential-backoff.py"
164+
--8<-- "examples/python/sdk-reference/error-handling/retry-strategy-signature.py"
24165
```
25166

26167
=== "Java"
27168

28169
```java
29-
--8<-- "examples/java/advanced/error-handling/exponential-backoff.java"
170+
--8<-- "examples/java/sdk-reference/error-handling/retry-strategy-signature.java"
30171
```
31172

32-
## RetryStrategyConfig parameters
173+
#### Example
174+
175+
=== "TypeScript"
176+
177+
Return `{ shouldRetry: false }` to stop, or
178+
`{ shouldRetry: true, delay: { seconds: N } }` to retry.
33179

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+
```
36183

37-
**initial_delay / initialDelay** Delay before the first retry. Default: 5 seconds.
184+
=== "Python"
38185

39-
**max_delay / maxDelay** Maximum delay between retries. Default: 5 minutes.
186+
Use `RetryDecision.retry(Duration)` or `RetryDecision.no_retry()`.
40187

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+
```
42191

43-
**jitter_strategy / jitter** Jitter strategy to spread retries. Default: `FULL`.
192+
=== "Java"
44193

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()`.
47195

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+
```
50199

51200
## Retry presets
52201

202+
The SDK ships with preset strategies for common cases:
203+
53204
=== "TypeScript"
54205

55206
```typescript
56-
--8<-- "examples/typescript/advanced/error-handling/retry-presets.ts"
207+
--8<-- "examples/typescript/sdk-reference/error-handling/retry-presets.ts"
57208
```
58209

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+
59215
=== "Python"
60216

61217
```python
62-
--8<-- "examples/python/advanced/error-handling/retry-presets.py"
218+
--8<-- "examples/python/sdk-reference/error-handling/retry-presets.py"
63219
```
64220

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+
65234
=== "Java"
66235

67236
```java
68-
--8<-- "examples/java/advanced/error-handling/retry-presets.java"
237+
--8<-- "examples/java/sdk-reference/error-handling/retry-presets.java"
69238
```
70239

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.
72248

73249
=== "TypeScript"
74250

251+
Use `retryableErrorTypes` to specify which error classes to retry.
252+
75253
```typescript
76-
--8<-- "examples/typescript/sdk-reference/error-handling/unreliable-operation.ts"
254+
--8<-- "examples/typescript/sdk-reference/error-handling/retry-specific-errors.ts"
77255
```
78256

79257
=== "Python"
80258

259+
Use `retryable_error_types` to specify which exception classes to retry.
260+
81261
```python
82-
--8<-- "examples/python/sdk-reference/error-handling/unreliable-operation.py"
262+
--8<-- "examples/python/sdk-reference/error-handling/retry-specific-errors.py"
83263
```
84264

85265
=== "Java"
86266

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+
87270
```java
88-
--8<-- "examples/java/sdk-reference/error-handling/unreliable-operation.java"
271+
--8<-- "examples/java/sdk-reference/error-handling/retry-specific-errors.java"
89272
```
90273

91274
## See also

examples/java/advanced/error-handling/basic-error-handling.java

Lines changed: 0 additions & 1 deletion
This file was deleted.

examples/java/advanced/error-handling/retry-presets.java

Lines changed: 0 additions & 1 deletion
This file was deleted.

examples/java/advanced/error-handling/serdes-error.java

Lines changed: 0 additions & 1 deletion
This file was deleted.

examples/java/advanced/error-handling/step-interrupted.java

Lines changed: 0 additions & 1 deletion
This file was deleted.

examples/java/advanced/error-handling/validation-error.java

Lines changed: 0 additions & 1 deletion
This file was deleted.

examples/java/advanced/error-handling/base-exception.java renamed to examples/java/sdk-reference/error-handling/base-exception.java

File renamed without changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import java.util.Map;
2+
import software.amazon.lambda.durable.DurableContext;
3+
import software.amazon.lambda.durable.DurableHandler;
4+
import software.amazon.lambda.durable.exception.StepFailedException;
5+
6+
public class BasicErrorHandling extends DurableHandler<Map<String, String>, Map<String, Object>> {
7+
8+
@Override
9+
public Map<String, Object> handleRequest(Map<String, String> event, DurableContext context) {
10+
try {
11+
Map<String, String> result = context.step("process-order", Map.class, stepCtx -> {
12+
String orderId = event.get("orderId");
13+
if (orderId == null || orderId.isEmpty()) {
14+
throw new IllegalArgumentException("orderId is required");
15+
}
16+
return Map.of("orderId", orderId, "status", "processed");
17+
});
18+
return Map.of("result", result);
19+
} catch (StepFailedException e) {
20+
context.getLogger().error("Step failed: " + e.getMessage());
21+
return Map.of("error", e.getErrorObject().errorMessage());
22+
}
23+
}
24+
}

examples/java/advanced/error-handling/callback-error.java renamed to examples/java/sdk-reference/error-handling/callback-error.java

File renamed without changes.

0 commit comments

Comments
 (0)