reliakit-retry
A small, runtime-agnostic retry helper for Rust operations that may fail temporarily.
reliakit-retry turns a reliakit-backoff
schedule and an attempt limit into a RetryPolicy, then drives a fallible
operation against it — synchronously or asynchronously. It decides whether to
retry and how long the gap should be, but it never sleeps, spawns, or assumes
an async runtime: you inject the waiting.
It has no third-party dependencies, forbids unsafe code, and is no_std-friendly
(no allocation, no clock).
What problem it solves
Transient failures — a flaky network call, a momentarily busy resource — are worth retrying a few times with growing gaps. Writing that loop by hand each time means re-deriving attempt counting, backoff, and "is this error even worth retrying" every time. This crate is that loop, made explicit and reusable, with no opinion about how you wait.
When to use it
- You retry a fallible operation and want clear attempt limits and backoff.
- You want to retry only some errors (transient) and fail fast on others.
- You want one retry helper that works in sync code, async code, and
no_std.
When not to use it
- You want a framework, middleware stack, or a Tower-style layer system. This is a single function, not infrastructure.
- You want the crate to sleep, spawn, log, or schedule for you. It does none of that by design — you provide the sleeper.
Installation
[]
= "0.1"
For no_std (pure core, no std::error::Error impl):
[]
= { = "0.1", = false }
Basic sync example
use Duration;
use ;
let policy = new
.unwrap;
let mut attempt = 0;
let result: = retry_with_sleep;
assert_eq!;
Use retry(&policy, op, should_retry) for the same logic with no waiting at all.
Async example (user-provided sleep, no runtime)
use Duration;
use ;
# async
retry_async uses only core::future::Future; it does not depend on Tokio,
async-std, or futures. The async_retry example shows it running under a tiny
in-file executor with no runtime at all.
Attempt counting
max_attempts is the total number of attempts, including the first:
max_attempts = 1→ try once, never retry.max_attempts = 3→ the first try plus up to two retries.max_attempts = 0→ rejected byRetryPolicy::new(returnsNone).
The attempt count is the single authority for how many times the operation runs.
The Backoff is consulted only for the delay before each retry; if it yields no
delay, Duration::ZERO is used, so the two limits never conflict.
Feature flags
| Flag | Default | Description |
|---|---|---|
std |
yes | Adds impl std::error::Error for RetryError. Otherwise the crate is pure core. |
no_std
reliakit-retry is no_std-friendly and needs no allocation and no clock. With
--no-default-features it builds for bare-metal targets; only the
std::error::Error impl is gated off.
Design notes
- It never sleeps. Blocking a thread or awaiting a runtime timer is hidden behavior and ties the helper to one execution model. You pass the sleeper.
- Clock-agnostic. Delays come from the backoff schedule by attempt index, so
no wall-clock is read;
reliakit-core::Clockis not needed. - Runtime-agnostic async. The async helper awaits a future you supply, so it runs under any executor.
- Built on the family. The backoff schedule is
reliakit-backoff::Backoff, re-exported here asreliakit_retry::Backoff.
Safety
This crate is #![forbid(unsafe_code)].
Status
Pre-1.0. The API is small and stable; it may receive backward-compatible
refinements before a 1.0 release. Minimum supported Rust version: 1.85.
License
Licensed under the MIT License. See LICENSE.