pub trait LockingPlugin: Send + Sync {
// Required methods
fn name(&self) -> &str;
fn try_lock(
&self,
key: &str,
ttl_ms: u64,
) -> Result<Option<LockHandle>, String>;
fn renew(&self, handle: &LockHandle) -> Result<(), String>;
fn release(&self, handle: LockHandle) -> Result<(), String>;
// Provided method
fn cleanup(&self) -> Result<(), String> { ... }
}Expand description
A plugin that provides distributed mutual exclusion.
Compile-time and WASM execution. All methods use JSON-friendly POD types so the trait is ABI-compatible with WASM guest plugins (matches the convention used by the other capability traits in this crate). Backends that need a real async client run their own runtime inside the call.
Concurrency: implementations MUST be safe to call from multiple threads simultaneously. The host may contend on the same key from different request-handling threads.
Required Methods§
Sourcefn name(&self) -> &str
fn name(&self) -> &str
Unique plugin name (e.g., "memory", "redis", "pg"). Used
by the dev dashboard, metrics labels, and cap_conformance.
Sourcefn try_lock(&self, key: &str, ttl_ms: u64) -> Result<Option<LockHandle>, String>
fn try_lock(&self, key: &str, ttl_ms: u64) -> Result<Option<LockHandle>, String>
Attempt to acquire the lock identified by key for at most
ttl_ms milliseconds.
§Return shape
Ok(Some(handle))— the lock was acquired. The caller owns it forttl_msand may renew or release.Ok(None)— contention. Another owner holds the lock. The caller typically backs off and retries later, or simply skips this run (the Scheduled capability skips).Err(message)— backend failure (network, protocol, configuration). The caller cannot meaningfully retry without operator intervention.
The Ok(None) vs Err(..) distinction is the reason this trait
does not use a typed LockError enum — it is the only branch
that matters to 99% of callers, and encoding it in the outer
Result is cleaner than a LockError::Held variant they would
have to match every single call site.
Sourcefn renew(&self, handle: &LockHandle) -> Result<(), String>
fn renew(&self, handle: &LockHandle) -> Result<(), String>
Extend the lifetime of an existing lock.
On success the lock’s TTL is reset to handle.ttl_ms. On
failure — either because the lock has already expired or the
backend is broken — returns Err(message). Callers treat the
failure uniformly: “you no longer own this lock; stop holding
it.” The default retry policy is to abandon the work and try
try_lock again from scratch on the next opportunity.
Sourcefn release(&self, handle: LockHandle) -> Result<(), String>
fn release(&self, handle: LockHandle) -> Result<(), String>
Release the lock.
Implementations MUST verify that the lock is still held under
the caller’s handle.lock_id before releasing (check-and-set),
so a stale call after the TTL expired cannot clobber a newer
holder. Releasing a lock the caller does not own is a silent
no-op, not an error.