Update the status before tearing the socket down in closeSocket - #1609
Update the status before tearing the socket down in closeSocket#1609scottf wants to merge 1 commit into
Conversation
closeSocketImpl clears the current server as its first statement and then waits on the reader and writer stop futures, so updating the status afterwards left a window where getStatus() returned CONNECTED while getConnectedUrl() returned null. Moves updateStatus(DISCONNECTED) into the block that already sets disconnecting, after wasConnected is captured. This is the order forceReconnectImpl already used. Fixes #1608
|
Claude finished @scottf's task in 2m 24s —— View job PR Review
SummaryThe fix is correct and well-scoped. The root cause is clear: The concurrency analysis in the PR description is accurate. No new issues are introduced. Thread Safety
One Harmless RedundancyAfter the move, Observable Behavioral ChangeThe
|
Fixes #1608
Fixes the window where
getStatus()returnsCONNECTEDwhilegetConnectedUrl()returns null.closeSocketcalledcloseSocketImpl(forceClose)and updated the status afterwards. SincecloseSocketImplclears the current server as its first statement and then waits on the reader and writer stop futures (1 second each), everything between those two points reported a connection that was CONNECTED to nowhere. Any health check, metric or log line sampling the connection during a communication failure teardown could see it, with no callback delay involved.The change moves
updateStatus(Status.DISCONNECTED)up into the block that already setsdisconnecting = true, afterwasConnectedis captured so the reconnect decision is unaffected:This is the order
forceReconnectImplalready used, so the four paths that touch both fields now agree.Notes for review
wasConnectedis captured before the status update, soelse if (wasConnected && tryReconnectIfConnected)still behaves the same.updateStatustakesstatusLock, which is reentrant and was already being taken this way in the block that was removed.DISCONNECTEDevent now fires before the reader and writer are stopped rather than after. Delivery was always asynchronous on the callback executor so nothing was tightly sequenced against it, but it is the one observable change and worth a second opinion.updateStatus(Status.DISCONNECTED)derives itsuriDetailsfromcurrentServer == null ? lastServer : currentServer. Running beforeclearCurrentServer()means it now takes the value fromcurrentServerdirectly instead of thelastServerfallback. Same string either way, sinceclearCurrentServer()copies one into the other.exceptionDuringConnectChange = nullanddisconnecting = falsestay aftercloseSocketImpl, unchanged.Test
ConnectionStateConsistencyTests.testStatusAndConnectedUrlAreNeverInconsistentDuringTeardownpolls both fields from a thread while the server is killed, and asserts the pair is never observed inconsistent.It fails on the unfixed code and passes with the change:
The test kills the server rather than calling
forceReconnect(), deliberately —forceReconnectgoes throughforceReconnectImpl, which was already correct, and a test driven that way passes with or without the fix.