|
| 1 | +--- |
| 2 | +title: Durable Functions |
| 3 | +description: Using Powertools for AWS Lambda (Python) with Lambda Durable Functions |
| 4 | +--- |
| 5 | + |
| 6 | +<!-- markdownlint-disable MD043 --> |
| 7 | + |
| 8 | +[Lambda Durable Functions](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html){target="_blank" rel="nofollow"} enable you to build resilient multi-step workflows that can execute for up to one year. They use checkpoints to track progress and automatically recover from failures through replay. |
| 9 | + |
| 10 | +## Key concepts |
| 11 | + |
| 12 | +| Concept | Description | |
| 13 | +| --------------------- | ------------------------------------------------------------------ | |
| 14 | +| **Durable execution** | Complete lifecycle of a durable function, from start to completion | |
| 15 | +| **Checkpoint** | Saved state that tracks progress through the workflow | |
| 16 | +| **Replay** | Re-execution from the beginning, skipping completed checkpoints | |
| 17 | +| **Step** | Business logic with built-in retries and progress tracking | |
| 18 | +| **Wait** | Suspend execution without incurring compute charges | |
| 19 | + |
| 20 | +## How it works |
| 21 | + |
| 22 | +Durable functions use a **checkpoint/replay mechanism**: |
| 23 | + |
| 24 | +1. Your code runs always from the beginning |
| 25 | +2. Completed operations are skipped using stored results |
| 26 | +3. Execution of new steps continues from where it left off |
| 27 | +4. State is automatically managed by the SDK |
| 28 | + |
| 29 | +## Powertools integration |
| 30 | + |
| 31 | +Powertools for AWS Lambda (Python) works seamlessly with Durable Functions. The [Durable Execution SDK](https://github.com/aws/aws-durable-execution-sdk-python){target="_blank" rel="nofollow"} has native integration with Logger via `context.set_logger()`. |
| 32 | + |
| 33 | +???+ note "Found an issue?" |
| 34 | + If you encounter any issues using Powertools for AWS Lambda (Python) with Durable Functions, please [open an issue](https://github.com/aws-powertools/powertools-lambda-python/issues/new?template=bug_report.yml){target="_blank"}. |
| 35 | + |
| 36 | +### Logger |
| 37 | + |
| 38 | +The Durable Execution SDK provides a `context.logger` instance that automatically handles **log deduplication during replays**. You can integrate Logger to get structured JSON logging while keeping the deduplication benefits. |
| 39 | + |
| 40 | +For the best experience, set the Logger on the durable context. This gives you structured JSON logging with automatic log deduplication during replays: |
| 41 | + |
| 42 | +```python hl_lines="5 8 12 15" title="Integrating Logger with Durable Functions" |
| 43 | +--8<-- "examples/lambda_features/durable_functions/src/using_logger.py" |
| 44 | +``` |
| 45 | + |
| 46 | +This gives you: |
| 47 | + |
| 48 | +- **JSON structured logging** from Powertools for AWS Lambda (Python) |
| 49 | +- **Log deduplication** during replays (logs from completed operations don't repeat) |
| 50 | +- **Automatic SDK enrichment** (execution_arn, parent_id, name, attempt) |
| 51 | +- **Lambda context injection** (request_id, function_name, etc.) |
| 52 | + |
| 53 | +???+ warning "Direct logger usage" |
| 54 | + If you use the Logger directly (not through `context.logger`), logs will be emitted on every replay: |
| 55 | + |
| 56 | + ```python |
| 57 | + # Logs will duplicate during replays |
| 58 | + logger.info("This appears on every replay") |
| 59 | + |
| 60 | + # Use context.logger instead for deduplication |
| 61 | + context.logger.info("This appears only once") |
| 62 | + ``` |
| 63 | + |
| 64 | +### Tracer |
| 65 | + |
| 66 | +Tracer works with Durable Functions. Each execution creates trace segments. |
| 67 | + |
| 68 | +???+ note "Trace continuity" |
| 69 | + Due to the replay mechanism, traces may be interleaved. Each execution (including replays) creates separate trace segments. Use the `execution_arn` to correlate traces. |
| 70 | + |
| 71 | +```python hl_lines="5-6 9-10" title="Using Tracer with Durable Functions" |
| 72 | +--8<-- "examples/lambda_features/durable_functions/src/using_tracer.py" |
| 73 | +``` |
| 74 | + |
| 75 | +### Metrics |
| 76 | + |
| 77 | +Metrics work with Durable Functions, but be aware that **metrics may be emitted multiple times** during replay if not handled carefully. Emit metrics at workflow completion rather than during intermediate steps to avoid counting replays as new executions. |
| 78 | + |
| 79 | +```python hl_lines="6 9 18 19 20 21" title="Using Metrics with Durable Functions" |
| 80 | +--8<-- "examples/lambda_features/durable_functions/src/best_practice_metrics.py" |
| 81 | +``` |
| 82 | + |
| 83 | +### Idempotency |
| 84 | + |
| 85 | +The `@idempotent` decorator integrates with Durable Functions and is **replay-aware**. It's useful for protecting the Lambda handler entry point, especially for Event Source Mapping (ESM) invocations like SQS, Kinesis, or DynamoDB Streams. |
| 86 | + |
| 87 | +```python hl_lines="8 15" title="Using Idempotency with Durable Functions" |
| 88 | +--8<-- "examples/lambda_features/durable_functions/src/using_idempotency.py" |
| 89 | +``` |
| 90 | + |
| 91 | +???+ warning "Decorator ordering matters" |
| 92 | + The `@idempotent` decorator must be placed **above** `@durable_execution`. This ensures the idempotency check runs first, preventing duplicate executions before the durable workflow begins. Reversing the order would cause the durable execution to start before the idempotency check, defeating its purpose. |
| 93 | + |
| 94 | +**When to use Powertools Idempotency:** |
| 95 | + |
| 96 | +- Protecting the Lambda handler entry point from duplicate invocations |
| 97 | +- Methods you don't want to convert into steps but need idempotency guarantees |
| 98 | +- Event Source Mapping triggers (SQS, Kinesis, DynamoDB Streams) |
| 99 | + |
| 100 | +**When you don't need it:** |
| 101 | + |
| 102 | +- Steps within a durable function are already idempotent via the checkpoint mechanism |
| 103 | + |
| 104 | +### Parameters |
| 105 | + |
| 106 | +Parameters work normally with Durable Functions. |
| 107 | + |
| 108 | +```python hl_lines="13" title="Using Parameters with Durable Functions" |
| 109 | +--8<-- "examples/lambda_features/durable_functions/src/using_parameters.py" |
| 110 | +``` |
| 111 | + |
| 112 | +???+ note "Parameter freshness" |
| 113 | + If the replay or execution happens within the cache TTL on the same execution environment, the parameter value may come from cache. For long-running workflows (hours/days), parameters fetched at the start may become stale. Consider fetching parameters within steps that need the latest values, and customize the caching behavior with `max_age` to control freshness. |
| 114 | + |
| 115 | +## Best practices |
| 116 | + |
| 117 | +### Use Idempotency for ESM triggers |
| 118 | + |
| 119 | +When your durable function is triggered by Event Source Mappings (SQS, Kinesis, DynamoDB Streams), use the `@idempotent` decorator to protect against duplicate invocations. |
| 120 | + |
| 121 | +```python title="Idempotency for ESM" |
| 122 | +--8<-- "examples/lambda_features/durable_functions/src/best_practice_idempotency.py" |
| 123 | +``` |
| 124 | + |
| 125 | +## FAQ |
| 126 | + |
| 127 | +### Do I need Idempotency utility with Durable Functions? |
| 128 | + |
| 129 | +It depends on your use case. Steps within a durable function are already idempotent via checkpoints. However, the `@idempotent` decorator is useful for protecting the Lambda handler entry point, especially for Event Source Mapping invocations (SQS, Kinesis, DynamoDB Streams) where the same event might trigger multiple invocations. |
| 130 | + |
| 131 | +### Why do I see duplicate logs? |
| 132 | + |
| 133 | +If you're using the logger directly instead of `context.logger`, logs will be emitted on every replay. Use `context.set_logger(logger)` and then `context.logger.info()` to get automatic log deduplication. |
| 134 | + |
| 135 | +### How do I correlate logs across replays? |
| 136 | + |
| 137 | +Use the `execution_arn` field that's automatically added to every log entry when using `context.logger`: |
| 138 | + |
| 139 | +```sql |
| 140 | +fields @timestamp, @message, execution_arn |
| 141 | +| filter execution_arn = "arn:aws:lambda:us-east-1:123456789012:function:my-function:execution-id" |
| 142 | +| sort @timestamp asc |
| 143 | +``` |
| 144 | + |
| 145 | +### Can I use Tracer with Durable Functions? |
| 146 | + |
| 147 | +Yes, but be aware that each execution (including replays) creates separate trace segments. Use the `execution_arn` as a correlation identifier for end-to-end visibility. |
| 148 | + |
| 149 | +### How should I emit metrics without duplicates? |
| 150 | + |
| 151 | +Emit metrics at workflow completion rather than during intermediate steps. This ensures you count completed workflows, not replay attempts. |
0 commit comments