retry adds per-attempt timeout, retry/backoff, and optional semaphore-based concurrency control around async functions (including bus handlers).
Signature
- Python
- TypeScript
Options
| Option | Description |
|---|---|
max_attempts | Total attempts including the first call (1 disables retries). |
retry_after | Base delay between retries, in seconds. |
retry_backoff_factor | Delay multiplier applied after each failed attempt. |
retry_on_errors | Optional matcher list to restrict which errors are retried. |
timeout | Per-attempt timeout in seconds (None/undefined means no per-attempt timeout). |
semaphore_limit | Max concurrent executions sharing the same semaphore. |
semaphore_name | Semaphore key (string or function deriving a key from call args). |
semaphore_scope | Semaphore sharing scope (global, class, instance; Python also supports multiprocess). |
semaphore_timeout | Max wait time for semaphore acquisition before timeout/lax fallback. |
semaphore_lax | If true, continue execution without semaphore limit when acquisition times out. |
Example: Inline wrapper
- Python
- TypeScript
Example: Decorated class method
- Python
- TypeScript
Behavior
- Semaphore acquisition happens once per call, then all retry attempts run within that acquired slot.
- Backoff delay per retry is:
retry_after * retry_backoff_factor^(attempt - 1). - Retries stop immediately when the thrown error does not match
retry_on_errors. - Bus/event timeouts act as outer execution budgets;
retry.timeoutis per-attempt.
Runtime differences
- Python supports semaphore scope
multiprocessin addition toglobal,class, andinstance. - TypeScript supports
global,class, andinstance, and uses async-context re-entrancy tracking in Node/Bun to avoid same-semaphore nested deadlocks. retry_on_errorsmatching differs slightly:- Python: exception classes or compiled regex patterns (matched against
"ErrorClass: message"). - TypeScript: error constructors, error-name strings, or regex patterns.
- Python: exception classes or compiled regex patterns (matched against