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:
select
returns as soon as the first future completes, whilewait_completed
waits for at least one to complete and returns both completed and pending futures. - Use cases:
- Use
select
when you want to race multiple operations and act on whichever completes first. - Use
wait_completed
when you want to handle completed futures immediately while potentially canceling or managing pending ones,
- Use
- Pattern matching:
select
uses pattern matching to determine which future completed, whilewait_completed
separates 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: