Repository navigation
Make outgoing pending count getters non-blocking - #1632
Conversation
Remove closeSocketLock and writerLock from outgoingPendingMessageCount and outgoingPendingBytes. The counters are atomics, and neither lock serializes with the code that changes them, so the locks added nothing except parking callers behind an in-flight socket write and, on the closeSocket path, behind the entire reconnect. The closeSocketLock guarded a writer swap on reconnect that was removed in 2.25.2. Adds a regression test that reads both getters while another thread holds closeSocketLock. Resolves #1631
|
Claude finished @scottf's task in 43s —— View job Review complete
Verified the core claim. Correctness/thread-safety: No issues. The getters now do a plain volatile-backed Test: API compatibility: Return values change from Minor, non-blocking observation: the comment on No blocking issues found. |
|
On the |
State the assign-once invariant on writer precisely: the field is protected rather than final for custom Connection implementations, and nothing reassigns it after the constructor. Raised by the PR review.
Resolves #1631
Connection.outgoingPendingMessageCount()andoutgoingPendingBytes()tookcloseSocketLockinNatsConnectionandwriterLockinNatsConnectionWriterto return twoAtomicLongvalues. Neither lock is held by any code that changes those counters (push,accumulate,filter), so they added no consistency. What they did add:writerLockparked the caller behind an in-flightsendMessageBatch, bounded only by the socket write timeout (default 1 minute), andcloseSocketLockparked the caller for the entire reconnect, sincecloseSocketholds it throughreconnectImpl().publishInternaltakes neither lock, so an application that reads the getter once per publish was blocked for the whole reconnect while plain publishes would have kept buffering.The
closeSocketLockwas added in #1416 (2.23.0) because the writer was replaced on every reconnect at that time. That swap was removed in 2.25.2 (62f6325); the writer is now created once in the constructor and reused, so the lock has guarded nothing since. ThewriterLockand the null checks in the writer never guarded anything: the queue field has always beenprivate final. The analysis is in the issue.Changes
NatsConnection: both getters return the writer's value directly, nocloseSocketLock.NatsConnectionWriter: both getters returnnormalOutgoing.length()/sizeInBytes()directly, nowriterLock, no null checks. This restores the Expose connection outgoingPendingMessageCount and outgoingPendingBytes #1412 bodies.NatsConnectionImplTests: newtestOutgoingPendingGettersDoNotBlockOnCloseSocketLockholdscloseSocketLockon the test thread and reads both getters from another thread under a timeout. Trimmed the now-stale comment intestOutgoingPendingCountCoverage.Verification
NatsConnectionImplTests: 5 tests, 0 failures, 0 errors.mainin a separate worktree fails on all 5 retry attempts withjava.util.concurrent.TimeoutException.🤖 Generated with Claude Code