Problem
The passive connection always uses a shared ApPassiveServerPool that wraps the same underlying pool as the active connection. There is no way to supply a custom pool for the passive connection.
Root cause: Both active and passive connections share one underlying ServerPool instance. Both call connectSucceeded(), which sets lastConnected — a shared field that races between the two connections. The pool's sort and push-to-end decisions must use the active server as the reference, but lastConnected reflects whichever connection called connectSucceeded() last.
We have a partial internal workaround on the active-connection side, but the passive connection still draws from the same shared pool instance and cannot independently apply its own server selection policy (e.g. local-AZ priority while also avoiding the active server).
Current workaround
We subclass the existing server pool and override its sort and push-to-end decisions to use the known active server URI as the stable reference, rather than the shared lastConnected field that races between the two connections. This resolves the ordering problem for the active connection. However, because the passive connection draws from the same pool instance, it still cannot apply an independent selection policy — for example, it cannot simultaneously enforce local-AZ preference and avoid the active server. A dedicated passive pool with library-level setActiveServer() notification is the correct solution.
Proposed API addition
// In ApOptions.Builder
/**
* Supply a dedicated server pool for the passive connection.
* If the pool implements ActiveServerAware, ApConnection will call
* setActiveServer() after each active (re)connect so the passive pool
* can independently avoid the active server.
*
* If not supplied, the default shared ApPassiveServerPool is used.
*/
public Builder passiveServerPool(ServerPool passiveServerPool) {
this.passiveServerPool = passiveServerPool;
return this;
}
Also requires an ActiveServerAware interface in the public-facing io.nats.client package (not impl) so it is accessible without split-package access:
// New interface in io.nats.client
/**
* Implemented by server pools that need to know which server the active
* connection is currently using, so they can avoid it when selecting
* a target for the passive connection.
*/
public interface ActiveServerAware {
void setActiveServer(NatsUri nuri);
}
And in ApConnection, after each active (re)connect:
// In connect() and reconnectImplConnect() — after setting currentServer
if (passivePool instanceof ActiveServerAware) {
((ActiveServerAware) passivePool).setActiveServer(currentServer);
}
We are ready to adopt this API as soon as it is available.
Problem
The passive connection always uses a shared
ApPassiveServerPoolthat wraps the same underlying pool as the active connection. There is no way to supply a custom pool for the passive connection.Root cause: Both active and passive connections share one underlying
ServerPoolinstance. Both callconnectSucceeded(), which setslastConnected— a shared field that races between the two connections. The pool's sort and push-to-end decisions must use the active server as the reference, butlastConnectedreflects whichever connection calledconnectSucceeded()last.We have a partial internal workaround on the active-connection side, but the passive connection still draws from the same shared pool instance and cannot independently apply its own server selection policy (e.g. local-AZ priority while also avoiding the active server).
Current workaround
We subclass the existing server pool and override its sort and push-to-end decisions to use the known active server URI as the stable reference, rather than the shared
lastConnectedfield that races between the two connections. This resolves the ordering problem for the active connection. However, because the passive connection draws from the same pool instance, it still cannot apply an independent selection policy — for example, it cannot simultaneously enforce local-AZ preference and avoid the active server. A dedicated passive pool with library-levelsetActiveServer()notification is the correct solution.Proposed API addition
Also requires an
ActiveServerAwareinterface in the public-facingio.nats.clientpackage (notimpl) so it is accessible without split-package access:And in
ApConnection, after each active (re)connect:We are ready to adopt this API as soon as it is available.