Skip to main content

Crate sisyphus

Crate sisyphus 

Source
Expand description

§sisyphus

A generic, execution-agnostic and time-agnostic backoff & retry utility, built as a pure state machine.

Sisyphus was condemned by the gods to roll a boulder up a hill for eternity, only to watch it roll back down every time — the original retry loop. This crate is the part of that punishment worth keeping: it computes when to push the boulder again, and nothing else.

§Why another retry crate?

Most retry crates (e.g. backoff) bake in std::time::Instant and std::thread::sleep, coupling policy (how long to wait) with execution (how to wait). That falls apart in:

  • WebAssembly engines executing Wasm directly, with no host threads;
  • Deterministic blockchain / consensus state machines, where wall-clock reads and panics are forbidden;
  • no_std embedded targets with no allocator and no std::time.

sisyphus solves this by being a pure state machine:

  • #![no_std], zero allocation, no dyn (unless you opt in).
  • Time is just core::time::Duration; instants come from your Clock.
  • Randomness/jitter is injected via Jitter (deterministic by default).
  • Execution is driven by your sleep — sync closure or async future.

§30-second tour

use core::ops::ControlFlow;
use core::time::Duration;
use sisyphus::{retry_sync, ExponentialBackoff, PolicyExt, RetryError};

// 1. Build a policy by composing pure state machines.
let policy = ExponentialBackoff::new(Duration::from_millis(50), 2.0)
    .with_max_delay(Duration::from_secs(5))
    .max_attempts(4);

// 2. Drive it with your own operation + sleep. Here `sleep` just advances
//    a virtual clock, so the example runs instantly and deterministically.
let mut tries = 0u32;
let mut elapsed = Duration::ZERO;
let result: Result<&str, RetryError<&str>> = retry_sync(
    policy,
    || {
        tries += 1;
        if tries >= 3 { ControlFlow::Break("connected") }
        else { ControlFlow::Continue("connection refused") }
    },
    |delay| elapsed += delay, // plug in your real sleep in production
);

assert_eq!(result, Ok("connected"));

§Feature flags

featuredefaultadds
allocnoBoxedPolicy, impl BackoffPolicy for Box<dyn …>
stdnoSystemClock backed by std::time::Instant

The default build pulls in neither, keeping it pure-core and allocation-free.

Structs§

Constant
A policy that always returns the same fixed delay, forever.
ExponentialBackoff
Classic exponential backoff with optional injected jitter.
MaxAttempts
Caps the total number of delays an inner policy may produce.
MaxElapsedTime
Stops retrying once a wall-clock budget has elapsed.
NoJitter
A Jitter that adds no randomness at all.
SplitMix64
A tiny, fast, deterministic PRNG (Steele et al.’s SplitMix64).
SystemClockstd
A monotonic Clock backed by std::time::Instant.
WithMaxDelay
Caps the maximum delay returned by an inner policy.

Enums§

RetryError
The reason a retry loop stopped without a terminal ControlFlow::Break.

Traits§

BackoffPolicy
The core retry-timing state machine.
Clock
A source of monotonic time supplied by the host environment.
Jitter
A source of uniform randomness used to perturb backoff delays.
PolicyExt
Ergonomic, zero-cost combinators for any BackoffPolicy.

Functions§

retry_async
Drive an operation to completion asynchronously, backing off between tries.
retry_sync
Drive an operation to completion synchronously, backing off between tries.

Type Aliases§

BoxedPolicyalloc
A heap-allocated, type-erased BackoffPolicy.