Problem
The socket steal stops the old passive's reader and writer, but does not cancel its pingTask or cleanupTask. Because the old passive's status remains CONNECTED, pingTask continues calling softPing() and queuing PINGs through the stopped writer indefinitely.
Once the maxPingsOut limit is reached, jnats throws:
IllegalStateException: Max outgoing Ping count exceeded.
at NatsConnection.sendPing(NatsConnection.java:1694)
at NatsConnection.lambda$tryToConnect$8(NatsConnection.java:640) ← scheduled pingTask
at ScheduledTask.run(ScheduledTask.java:86)
This fires handleCommunicationIssue on the old passive, which spawns a background thread that calls NatsConnection.reconnectImplConnect() (base class) and loops through all servers getting "Connection refused" on each attempt — filling logs with errors and consuming thread resources.
Root cause
pingTask and cleanupTask are only stopped in NatsConnection.close(). The steal path never calls close() on the old passive (intentionally — calling close() would also close the stolen socket). There is no lower-level API to stop just the scheduled tasks without closing the socket.
Proposed fix
Expose pingTask and cleanupTask as stoppable via a dedicated method, or stop them as part of the steal sequence. Cancelling them immediately at steal time is sufficient:
NatsConnection oldPassive = this.passive;
this.passive = null;
// Cancel scheduled tasks before they cause unwanted reconnects on the zombie passive.
if (oldPassive.pingTask != null) { oldPassive.pingTask.shutdown(); oldPassive.pingTask = null; }
if (oldPassive.cleanupTask != null) { oldPassive.cleanupTask.shutdown(); oldPassive.cleanupTask = null; }
// ... null dataPort, stop reader/writer, steal socket ...
Current workaround
Applied directly in the local java-active-passive source until a release is available.
Problem
The socket steal stops the old passive's reader and writer, but does not cancel its
pingTaskorcleanupTask. Because the old passive's status remains CONNECTED,pingTaskcontinues callingsoftPing()and queuing PINGs through the stopped writer indefinitely.Once the
maxPingsOutlimit is reached, jnats throws:This fires
handleCommunicationIssueon the old passive, which spawns a background thread that callsNatsConnection.reconnectImplConnect()(base class) and loops through all servers getting "Connection refused" on each attempt — filling logs with errors and consuming thread resources.Root cause
pingTaskandcleanupTaskare only stopped inNatsConnection.close(). The steal path never callsclose()on the old passive (intentionally — callingclose()would also close the stolen socket). There is no lower-level API to stop just the scheduled tasks without closing the socket.Proposed fix
Expose
pingTaskandcleanupTaskas stoppable via a dedicated method, or stop them as part of the steal sequence. Cancelling them immediately at steal time is sufficient:Current workaround
Applied directly in the local java-active-passive source until a release is available.