Skip to content

Commit d83ec08

Browse files
committed
fix(client): connect nodes lazily in all-shards/all-nodes fan-out
getAllMasterClients/getAllClients silently skipped nodes without a connected client. With minimizeConnections (or a partially connected cluster) all_shards/all_nodes commands fanned out to a subset of nodes — or none, resolving undefined: PING via sendCommand returned undefined, DBSIZE could sum a subset without any error. Route through nodeClient(), the same lazy connect-or-reuse accessor keyed routing uses. getAllClients no longer yields dedicated PubSub connections; they cannot run regular commands. Also guard the policy dispatch against an empty fan-out — failing loud beats resolving undefined.
1 parent 7b252c1 commit d83ec08

2 files changed

Lines changed: 17 additions & 10 deletions

File tree

packages/client/lib/cluster/cluster-slots.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -792,18 +792,21 @@ export default class RedisClusterSlots<
792792
this.#emit('disconnect');
793793
}
794794

795-
getAllClients() {
796-
return Array.from(this.#clients());
795+
/**
796+
* All node clients (masters and replicas), connecting lazily — with
797+
* `minimizeConnections` nodes have no client until first use, and skipping
798+
* them would silently fan commands out to a subset of the cluster.
799+
* Excludes dedicated PubSub connections: they cannot run regular commands.
800+
*/
801+
getAllClients(): Promise<Array<RedisClientType<M, F, S, RESP, TYPE_MAPPING>>> {
802+
return Promise.all([
803+
...this.masters.map(master => this.nodeClient(master)),
804+
...this.replicas.map(replica => this.nodeClient(replica))
805+
]);
797806
}
798807

799-
getAllMasterClients() {
800-
const result = [];
801-
for (const master of this.masters) {
802-
if (master.client) {
803-
result.push(master.client);
804-
}
805-
}
806-
return result;
808+
getAllMasterClients(): Promise<Array<RedisClientType<M, F, S, RESP, TYPE_MAPPING>>> {
809+
return Promise.all(this.masters.map(master => this.nodeClient(master)));
807810
}
808811

809812
async getClientAndSlotNumber(

packages/client/lib/cluster/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,10 @@ export default class RedisCluster<
506506
const clients: Array<RedisClientType<M, F, S, RESP, TYPE_MAPPING>> =
507507
await router(this._slots, parser, isReadonly);
508508

509+
if (clients.length === 0) {
510+
throw new Error(`Request policy ${requestPolicy} produced no target nodes`);
511+
}
512+
509513
const responsePromises = clients.map(
510514
client => this._execute(parser, isReadonly, options, makeFn(parser), client)
511515
);

0 commit comments

Comments
 (0)