Skip to content

Proposal 9 — ApConnection.reconnectImplConnect(): pingTask / cleanupTask zombie after socket steal #11

@scottf

Description

@scottf

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions