Locks
Guard state & errors
Reading a guard's lease state and handling acquisition failures.
A lock guard tracks the state of its lease. Because the lease renews in the background, it's possible (rarely) for a guard to lose its lease mid-section - for instance, if Redis was briefly unreachable past the ttl. LockGuardState lets you observe that.
LockGuardState
pub enum LockGuardState {
Acquired, // held, lease is being renewed
Lost, // a refresh failed; the lease is presumed gone (may still recover)
Released, // released, no longer held
}
Every guard - MutexGuard, RwLockReadGuard, RwLockWriteGuard - exposes:
// Inspect the current state. No Redis round-trip.
async fn get_state(&self) -> LockGuardState;
// Release explicitly and return the resulting state.
async fn release(self) -> Result<LockGuardState, DistkitError>;
Checking before a critical section
Lost is the state to guard against: it means the lock may no longer be exclusively yours.
use distkit::lock::LockGuardState;
let guard = mutex.lock().await?;
match guard.get_state().await {
LockGuardState::Acquired => {
// safe - do the protected work
}
LockGuardState::Lost => {
// lease slipped; bail out instead of risking a double-run
return Ok(());
}
LockGuardState::Released => unreachable!("we still hold the guard"),
}
Acquisition errors
Acquiring can fail with a LockError (surfaced as DistkitError::LockError). The two you handle routinely mean "the lock is busy", not "something broke":
AcquireFail- a non-blockingtry_*call would have had to wait.Timeout { waited }- a bounded*_forcall ran out of time.
use distkit::{DistkitError, lock::LockError};
match mutex.try_lock().await {
Ok(guard) => { /* got it */ }
Err(DistkitError::LockError(LockError::AcquireFail)) => {
// someone else holds it - back off and retry later
}
Err(e) => return Err(e.into()),
}
The remaining variants (NotOwner, InvalidTtl, InvalidOwner) indicate misuse or bad configuration rather than contention.

