Skip to main content

with_metadata_file_lock

Function with_metadata_file_lock 

Source
pub async fn with_metadata_file_lock<T, F, Fut>(
    metadata_path: &Path,
    cycle: F,
) -> StorageResult<T>
where F: FnOnce() -> Fut, Fut: Future<Output = StorageResult<T>>,
Expand description

The blessed recipe for a multi-process consumer’s metadata read-modify-write cycle (#100, review composition fix): the advisory file lock (lock_file_for_metadata) is held across the whole awaited commit-actor cycle — cross-process exclusion and in-process actor serialization are both active for the duration of cycle.

The closure is async: a full load → mutate → publish cycle (including any save_*-style actor work) runs inside, while independent processes taking the same lock file serialize behind it. Lock acquisition runs on the blocking pool (the flock can park on a competing holder); the lock is released when the cycle’s future completes.

For consumers whose RMW is entirely synchronous, with_file_lock wraps the same lock file — but a sync closure cannot await the commit actor; only this helper composes the two locks.

§Operational caution (blocking-pool waits)

The flock wait is unbounded and runs through spawn_blocking, which Tokio documents for blocking work that is bounded and eventually completes: a waiter that has already parked cannot be reliably aborted, and many long-lived blocked waiters can exhaust the runtime’s blocking-thread capacity. This design is reasonable for metadata commits when:

  • commit cycles are short — the hold scope is a JSON load → mutate → publish, not compute;
  • contention is normally brief;
  • callers do not hold the lock across lengthy compute, network I/O, user interaction, or indefinite waits;
  • shutdown behavior with a stuck lock holder is understood: blocked spawn_blocking tasks are not aborted by task cancellation; tokio::runtime::Runtime::shutdown_timeout abandons them after a grace period while tokio::runtime::Runtime::shutdown_background waits them out — and process exit always closes the descriptor, releasing the flock.

If lock waits could be prolonged or numerous, prefer a dedicated lock-management thread, an explicit timeout/cancellation strategy (bounded wait before acquisition), or a storage system with transactional coordination over unbounded flock waits here.