@@ -869,25 +869,30 @@ private void CheckBacklogForTimeouts()
869869 while ( _backlog . TryPeek ( out Message ? message ) )
870870 {
871871 // See if the message has pass our async timeout threshold
872- // or has otherwise been completed (e.g. a sync wait timed out) which would have cleared the ResultBox
873- if ( ! message . HasTimedOut ( now , timeout , out var _ ) || message . ResultBox == null ) break ; // not a timeout - we can stop looking
872+ // Note: All timed out messages must be dequeued, even when no completion is needed, to be able to dequeue and complete other timed out messages.
873+ if ( ! message . HasTimedOut ( now , timeout , out var _ ) ) break ; // not a timeout - we can stop looking
874874 lock ( _backlog )
875875 {
876876 // Peek again since we didn't have lock before...
877877 // and rerun the exact same checks as above, note that it may be a different message now
878878 if ( ! _backlog . TryPeek ( out message ) ) break ;
879- if ( ! message . HasTimedOut ( now , timeout , out var _ ) && message . ResultBox != null ) break ;
879+ if ( ! message . HasTimedOut ( now , timeout , out var _ ) ) break ;
880880
881881 if ( ! BacklogTryDequeue ( out var message2 ) || ( message != message2 ) ) // consume it for real
882882 {
883883 throw new RedisException ( "Thread safety bug detected! A queue message disappeared while we had the backlog lock" ) ;
884884 }
885885 }
886886
887- // Tell the message it has failed
888- // Note: Attempting to *avoid* reentrancy/deadlock issues by not holding the lock while completing messages.
889- var ex = Multiplexer . GetException ( WriteResult . TimeoutBeforeWrite , message , ServerEndPoint ) ;
890- message . SetExceptionAndComplete ( ex , this ) ;
887+ // We only handle async timeouts here, synchronous timeouts are handled upstream.
888+ // Those sync timeouts happen in ConnectionMultiplexer.ExecuteSyncImpl() via Monitor.Wait.
889+ if ( message . ResultBoxIsAsync )
890+ {
891+ // Tell the message it has failed
892+ // Note: Attempting to *avoid* reentrancy/deadlock issues by not holding the lock while completing messages.
893+ var ex = Multiplexer . GetException ( WriteResult . TimeoutBeforeWrite , message , ServerEndPoint ) ;
894+ message . SetExceptionAndComplete ( ex , this ) ;
895+ }
891896 }
892897 }
893898
0 commit comments