microsoft/garnet · error · GarnetException

Failed to acquire inProgress lock at {nameof(PostSingleKeyCo

Error message

Failed to acquire inProgress lock at {nameof(PostSingleKeyConsistentReadCallback)}

What it means

Thrown by ReplicaReadSessionContext.PostSingleKeyConsistentReadCallback when TryReadLock() on the 'inProgress' SingleWriterMultiReaderLock fails. This is the post-read bookkeeping step (updating the maximum session sequence number); it requires a read lock and fails if a writer (Dispose) holds the lock.

Source

Thrown at libs/server/AOF/ReadConsistency/ReplicaReadSessionContext.cs:183

            try
            {
                appendOnlyFile.readConsistencyManager.PreSingleKeyConsistentRead(hash & long.MaxValue, ref replicaReadContext, readTimeout, consistentReadCts.Token);
            }
            finally
            {
                inProgress.ReadUnlock();
            }
        }

        /// <summary>
        /// Post read update maximum sequence number for a single key.
        /// </summary>
        /// <exception cref="GarnetException"></exception>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void PostSingleKeyConsistentReadCallback()
        {
            if (!inProgress.TryReadLock())
                throw new GarnetException($"Failed to acquire inProgress lock at {nameof(PostSingleKeyConsistentReadCallback)}");
            try
            {
                appendOnlyFile.readConsistencyManager.PostSingleKeyConsistentRead(ref replicaReadContext);
            }
            finally
            {
                inProgress.ReadUnlock();
            }
        }

        /// <summary>
        /// Initialize context for read key batch.
        /// </summary>
        /// <param name="parameters"></param>
        public void PreBatchKeyConsistentReadCallback(ReadOnlySpan<PinnedSpanByte> parameters)
        {
            if (!inProgress.TryReadLock())
                throw new GarnetException($"Failed to acquire inProgress lock at {nameof(PreBatchKeyConsistentReadCallback)}");

View on GitHub (pinned to 951b0fc683)

Solutions

  1. Drain in-flight reads before disposing the replica read session.
  2. Check a disposed flag before calling PostSingleKeyConsistentReadCallback.
  3. Catch GarnetException at the call site and treat the read as invalidated.
  4. Ensure the read pipeline completes (pre + post) within the session lifetime.

Example fix

// before
session.PostSingleKeyConsistentReadCallback(); // throws if disposing

// after
try { session.PostSingleKeyConsistentReadCallback(); }
catch (GarnetException) { /* session disposed mid-read; treat as stale */ }
Defensive patterns

Strategy: try-catch

Validate before calling

if (session.IsDisposed) return;
session.PostSingleKeyConsistentReadCallback();

Try / catch

try { session.PostSingleKeyConsistentReadCallback(); }
catch (GarnetException ex) when (ex.Message.Contains("inProgress lock"))
{ /* session disposed mid-read; result is stale, discard safely */ }

Prevention

When it happens

Trigger: The post-read callback runs after a single-key consistent read, but the session is concurrently being disposed (Dispose acquires the write lock). Since TryReadLock is non-blocking, it throws immediately.

Common situations: Session disposal racing with an in-flight read completion; a shutdown path that disposes sessions without draining outstanding reads; re-entrant access during dispose.

Related errors


AI-assisted analysis of microsoft/garnet@951b0fc683 (2026-08-13). Data as JSON: /api/errors/c49f24bed59e1a30. Report an issue: GitHub.