distkit
Concepts

Errors

One DistkitError enum, and a no-panic policy.

Library code in distkit never panics. Anything that can go wrong comes back through a single error type, DistkitError, so ? works uniformly across counters, locks, and rate limiting.

DistkitError

pub enum DistkitError {
    InvalidRedisKey(String),       // a key failed validation
    CounterError(CounterError),    // counter operation failed   (feature = "counter")
    LockError(LockError),          // lock operation failed       (feature = "lock")
    RedisError(redis::RedisError), // transport or Lua script error
    MutexPoisoned(&'static str),   // an internal sync primitive was poisoned
    CustomError(String),           // catch-all
    TrypemaError(TrypemaError),    // rate limiting failed        (feature = "trypema")
}

The feature-gated variants only exist when the matching feature is enabled, so you never match on a primitive you didn't compile in.

From is implemented for the inner error types, which is why ? just works:

let key = DistkitRedisKey::try_from("user_123".to_string())?; // InvalidRedisKey on failure
counter.inc(&key, 1).await?;                                  // RedisError / CounterError on failure

Lock errors

Lock-specific failures are modeled separately as LockError, surfaced through DistkitError::LockError:

pub enum LockError {
    AcquireFail,                  // a non-blocking acquire would have to wait
    Timeout { waited: Duration }, // a bounded acquire ran out of time
    NotOwner,                     // tried to release a lock you don't hold
    InvalidTtl(i64),              // ttl must be positive
    InvalidOwner,                 // owner id must not be empty
}

AcquireFail and Timeout are the two you handle routinely - they mean "the lock is busy", not "something broke". See Guard state & errors for how this interacts with lock guards.