#api #retry #deduplication

idempotent

Type-safe idempotency keys for building reliable, retry-safe APIs

2 unstable releases

Uses new Rust 2024

new 0.3.0 Mar 7, 2026
0.2.0 Mar 4, 2026
0.1.2 Mar 4, 2026
0.0.0 Jan 12, 2026

#546 in Web programming

MPL-2.0 license

63KB
1.5K SLoC

Build Status Crates.io Documentation MPL-2.0 license

idempotent

Idempotency library with at-most-once execution and response caching.

Highlights

  • Typestate entries: ProcessingCompleted is checked at compile time, so you can't forget to complete an entry or complete one twice
  • Pluggable stores: comes with an in-memory store and a Valkey/Redis store; implement IdempotencyStore for your own backend
  • Fencing tokens: rejects stale completions when a key expires and gets reclaimed while the original request is still running
  • Fingerprint matching: returns a conflict when a retry carries a different request body than the original; ships with an xxHash-based default, implement FingerprintStrategy for your own
  • UUID keys by default: IdempotencyKey::default() generates a random UUID v4

Usage

Add to your Cargo.toml

[dependencies]
idempotent = { version = "0.3.0", features = ["memory"] }

Quick example

use idempotent::{
    IdempotencyKey, IdempotencyEntry, IdempotencyStore,
    InsertResult, CachedResponse,
};
use idempotent::fingerprint::{DefaultFingerprintStrategy, FingerprintStrategy};
use idempotent::memory::MemoryStore;

let store = MemoryStore::new();
let key = IdempotencyKey::default();

let fingerprint = DefaultFingerprintStrategy.compute("POST /credentials/issue", b"VerifiableCredential");
let entry = IdempotencyEntry::new(fingerprint);

match store.try_insert(&key, entry).await? {
    InsertResult::Claimed { fencing_token, entry } => {
        // Execute your side effect (e.g. issue a verifiable credential)
        let response = issue_credential().await;

        let completed = entry.complete(CachedResponse::from(response));
        store.complete(&key, completed, fencing_token).await?;
    }
    InsertResult::Exists(existing) => {
        // Return the cached response or signal a conflict
    }
}

Optional features

  • memory: enables the in-memory store, suitable for development or single-node deployment
  • valkey: enables the Valkey/Redis store, using Lua scripts for atomic operations
  • tracing: instruments store operations with tracing spans and events
  • serde: derives Serialize and Deserialize on IdempotencyKey, IdempotencyEntry, Fingerprint, and FencingToken

Supported Rust versions

The minimum supported Rust version is 1.94.0.

License

Unless otherwise noted, this project is licensed under the Mozilla Public License Version 2.0.

Dependencies

~1–15MB
~142K SLoC