When to use concurrent tasks
Use concurrent tasks when you need to:- Call multiple external services simultaneously (e.g., fetching data from different APIs)
- Race multiple operations and use the first result (e.g., trying multiple LLM providers)
- Implement timeouts by racing an operation against a timer
- Perform batch operations where individual tasks can run in parallel
Key benefits
- Deterministic replay: Restate logs the order of completion, ensuring consistent behavior during failures
- Fault tolerance: If your handler fails, tasks that were already completed will be replayed with their results, while pending tasks will be retried
Parallelizing tasks
Start multiple durable operations concurrently by calling them without immediately awaiting:Retrieving results
Restate provides several patterns for coordinating concurrent tasks. All patterns useRestateDurableFuture combinators that log the order of completion, ensuring deterministic behavior during replays.
Waiting for first completion
There are two ways to do this.Select
Userestate.select() to race multiple operations and handle the first one that completes. This is ideal for implementing timeouts or waiting for external confirmations:
Wait completed
Userestate.wait_completed() when you want to wait for at least one task to complete.
This returns a tuple of two lists: the first list contains the futures that are completed,
the second list contains the futures that are not completed.
This gives you the option to, for example, cancel the pending futures:
Key Differences
- Return behavior:
selectreturns as soon as the first future completes, whilewait_completedwaits for at least one to complete and returns both completed and pending futures. - Use cases:
- Use
selectwhen you want to race multiple operations and act on whichever completes first. - Use
wait_completedwhen you want to handle completed futures immediately while potentially canceling or managing pending ones,
- Use
- Pattern matching:
selectuses pattern matching to determine which future completed, whilewait_completedseparates futures into completed and pending collections.
Waiting for all tasks to complete
Processing results as they complete
Userestate.as_completed() to process results in the order they finish: