2026-02-03 20:43:21 +01:00
2026-02-03 20:43:21 +01:00
2026-02-03 13:37:03 +01:00
2026-02-03 13:37:03 +01:00
2026-02-03 20:22:10 +01:00
2026-02-03 20:43:21 +01:00
2026-02-03 13:37:03 +01:00
2026-02-03 20:43:21 +01:00
2026-02-03 20:43:21 +01:00

noretry

A simple retry library for Rust with both sync and async support.

Usage

Async (enabled by default via the tokio feature):

let result = noretry::retry_async(|| async {
    do_something().await
})
.await
.map_err(|e| e.into_inner())?;

Sync:

let result = noretry::retry(|| {
    do_something()
})
.map_err(|e| e.into_inner())?;

Both use sensible defaults: 3 attempts, exponential backoff, 100ms initial delay, 30s cap, and jitter.

Errors returned from the closure are automatically treated as transient (retryable) via the From impl on Retryable. Use ? as normal and retries happen transparently.

Features

The tokio feature is enabled by default, providing retry_async and run_async. To use only the sync API:

noretry = { version = "0.1", default-features = false }

Builder

For more control, use the builder with run (sync) or run_async:

noretry::builder()
    .with_max_attempts(5)
    .with_linear_backoff()
    .build()
    .run_async(|| async {
        do_something().await
    })
    .await?;

Backoff strategies

Exponential backoff (default):

noretry::builder()
    .with_exponential_backoff()
    .build()

Linear backoff:

noretry::builder()
    .with_linear_backoff()
    .build()

Both strategies support configurable initial delay, max delay cap, and jitter (enabled by default):

use std::time::Duration;

noretry::builder()
    .with_initial_delay(Duration::from_millis(200))
    .with_max_delay(Duration::from_secs(10))
    .with_jitter(false)
    .build()

Permanent errors

If an error should not be retried, mark it as permanent using map_err:

use noretry::Retryable;

noretry::builder()
    .build()
    .run_async(|| async {
        do_something()
            .await
            .map_err(Retryable::permanent)?
    })
    .await;

The result is a RetryError::Permanent or RetryError::Exhausted, both of which carry the original error. Call .into_inner() to extract it.

Description
No description provided
Readme MIT 45 KiB
Languages
Rust 100%