Skip to content

Commit 74c045a

Browse files
committed
add info about retries to readme
Signed-off-by: Filinto Duran <[email protected]>
1 parent ae3c2df commit 74c045a

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ coverage-clean:
1111
rm -f .coverage .coverage.* coverage.xml
1212

1313
coverage-all: coverage-clean
14-
pytest -m "not e2e" --cov=durabletask --cov-branch --cov-report=term-missing --cov-report=xml
15-
pytest -m e2e --cov=durabletask --cov-branch --cov-report=term-missing --cov-report=xml --cov-append
14+
pytest -m "not e2e" --durations=0 --cov=durabletask --cov-branch --cov-report=term-missing --cov-report=xml
15+
pytest -m e2e --durations=0 --cov=durabletask --cov-branch --cov-report=term-missing --cov-report=xml --cov-append
1616

1717
install:
1818
python3 -m pip install .

README.md

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,62 @@ Orchestrations can be continued as new using the `continue_as_new` API. This API
126126

127127
Orchestrations can be suspended using the `suspend_orchestration` client API and will remain suspended until resumed using the `resume_orchestration` client API. A suspended orchestration will stop processing new events, but will continue to buffer any that happen to arrive until resumed, ensuring that no data is lost. An orchestration can also be terminated using the `terminate_orchestration` client API. Terminated orchestrations will stop processing new events and will discard any buffered events.
128128

129-
### Retry policies (TODO)
129+
### Retry policies
130130

131131
Orchestrations can specify retry policies for activities and sub-orchestrations. These policies control how many times and how frequently an activity or sub-orchestration will be retried in the event of a transient error.
132132

133+
#### Creating a retry policy
134+
135+
```python
136+
from datetime import timedelta
137+
from durabletask import task
138+
139+
retry_policy = task.RetryPolicy(
140+
first_retry_interval=timedelta(seconds=1), # Initial delay before first retry
141+
max_number_of_attempts=5, # Maximum total attempts (includes first attempt)
142+
backoff_coefficient=2.0, # Exponential backoff multiplier (must be >= 1)
143+
max_retry_interval=timedelta(seconds=30), # Cap on retry delay
144+
retry_timeout=timedelta(minutes=5), # Total time limit for all retries (optional)
145+
)
146+
```
147+
148+
**Notes:**
149+
- `max_number_of_attempts` **includes the initial attempt**. For example, `max_number_of_attempts=5` means 1 initial attempt + up to 4 retries.
150+
- `retry_timeout` is optional. If omitted or set to `None`, retries continue until `max_number_of_attempts` is reached.
151+
- `backoff_coefficient` controls exponential backoff: delay = `first_retry_interval * (backoff_coefficient ^ retry_number)`, capped by `max_retry_interval`.
152+
- `non_retryable_error_types` (optional) can specify additional exception types to treat as non-retryable (e.g., `[ValueError, TypeError]`). `NonRetryableError` is always non-retryable regardless of this setting.
153+
154+
#### Using retry policies
155+
156+
Apply retry policies to activities or sub-orchestrations:
157+
158+
```python
159+
def my_orchestrator(ctx: task.OrchestrationContext, input):
160+
# Retry an activity
161+
result = yield ctx.call_activity(my_activity, input=data, retry_policy=retry_policy)
162+
163+
# Retry a sub-orchestration
164+
result = yield ctx.call_sub_orchestrator(child_orchestrator, input=data, retry_policy=retry_policy)
165+
```
166+
167+
#### Non-retryable errors
168+
169+
For errors that should not be retried (e.g., validation failures, permanent errors), raise a `NonRetryableError`:
170+
171+
```python
172+
from durabletask.task import NonRetryableError
173+
174+
def my_activity(ctx: task.ActivityContext, input):
175+
if input is None:
176+
# This error will bypass retry logic and fail immediately
177+
raise NonRetryableError("Input cannot be None")
178+
179+
# Transient errors (network, timeouts, etc.) will be retried
180+
return call_external_service(input)
181+
```
182+
183+
Even with a retry policy configured, `NonRetryableError` will fail immediately without retrying.
184+
133185
## Getting Started
134186

135187
### Prerequisites

0 commit comments

Comments
 (0)