Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions docs/sdk-reference/error-handling/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ error and the operation details.
DOE --> InvokeError
DOE --> ChildContextError
DOE --> WaitForConditionError
SIE[StepInterruptedError]
SIE["StepInterruptedError (retryStrategy callback only)"]
```

```typescript
Expand All @@ -74,9 +74,11 @@ error and the operation details.
subclass corresponds to a specific operation type. The `cause` property holds the
original error your code threw.

`StepInterruptedError` is not a `DurableOperationError`. The SDK throws it when an
at-most-once step started but Lambda was interrupted before the SDK checkpointed the
result. See [Step interrupted](#step-interrupted) below.
The TypeScript SDK passes `StepInterruptedError` to your
`retryStrategy(error, attempt)` callback when Lambda interrupts an at-most-once step
before the SDK checkpoints the result. From `context.step(...)` the SDK throws a
`StepError` whose `cause.name` equals `"StepInterruptedError"`. See
[Step interrupted](#step-interrupted) below.

=== "Python"

Expand Down
15 changes: 9 additions & 6 deletions docs/sdk-reference/operations/step.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ The step will checkpoint the last error after exhausting all retry attempts.

**Returns:** `DurablePromise<T>`. Use `await` to get the result.

**Throws:** `DurableOperationError` wrapping the original error after retries are
exhausted. `StepInterruptedError` if an at-most-once step was interrupted.
**Throws:** `StepError` (a `DurableOperationError` subclass) wrapping the original
error after retries are exhausted. For an at-most-once step that Lambda interrupted
before the SDK checkpointed the result, the SDK throws a `StepError` whose
`cause.name` equals `"StepInterruptedError"`.

=== "Python"

Expand Down Expand Up @@ -208,10 +210,11 @@ The step will checkpoint the last error after exhausting all retry attempts.
```

- `AtLeastOncePerRetry` (default) Re-executes the step if the function replays before
the result is checkpointed. Safe for idempotent operations.
the SDK checkpoints the result. Safe for idempotent operations.
- `AtMostOncePerRetry` Executes the step at most once per retry attempt. If the function
replays before the result is checkpointed, the SDK skips the step and raises
`StepInterruptedError`. Use for operations with side effects.
replays before the SDK checkpoints the result, the SDK skips the step and throws a
`StepError` whose `cause.name` equals `"StepInterruptedError"`. Use for operations
with side effects.

=== "Python"

Expand Down Expand Up @@ -342,7 +345,7 @@ debugging easier.

=== "Java"

The name is always the first argument. Pass `null` for no name.
The name is always the first argument. Pass `null` for no name.

## Configuration

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ import {
} from "@aws/durable-execution-sdk-js";

// DurableOperationError
// StepError step failed after retries exhausted
// CallbackError callback operation failed
// CallbackTimeoutError callback timed out
// CallbackSubmitterError callback submitter failed
// InvokeError invoke operation failed
// ChildContextError child context failed
// WaitForConditionError wait-for-condition failed
// StepError: step failed after retries exhausted
// CallbackError: callback operation failed
// CallbackTimeoutError: callback timed out
// CallbackSubmitterError: callback submitter failed
// InvokeError: invoke operation failed
// ChildContextError: child context failed
// WaitForConditionError: wait-for-condition failed
//
// StepInterruptedError — at-most-once step interrupted before checkpoint
// (not a DurableOperationError; thrown directly)
// StepInterruptedError: internal sentinel. The SDK passes it to your
// retryStrategy(error, attempt) callback when Lambda interrupts an
// at-most-once step. From context.step(...) the SDK throws a StepError
// whose cause.name === "StepInterruptedError".

export {
DurableOperationError,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
withDurableExecution,
StepSemantics,
StepInterruptedError,
StepError,
} from "@aws/durable-execution-sdk-js";

export const handler = withDurableExecution(async (event, context) => {
Expand All @@ -15,11 +15,14 @@ export const handler = withDurableExecution(async (event, context) => {
);
return { status: "charged", result };
} catch (err) {
if (err instanceof StepInterruptedError) {
// The step started but Lambda was interrupted before the result was
// checkpointed. The SDK will not re-run the step on the next invocation.
// Inspect your payment system to determine whether the charge succeeded.
context.logger.warn("Payment step interrupted — check payment system");
if (
err instanceof StepError &&
err.cause?.name === "StepInterruptedError"
) {
// Lambda interrupted the step before the SDK checkpointed the result.
// The SDK will not re-run the step on the next invocation. Check your
// payment system to determine whether the charge succeeded.
context.logger.warn("Payment step interrupted; check payment system");
return { status: "unknown" };
}
throw err;
Expand Down