diff --git a/docs/clustering.md b/docs/clustering.md index c43d63407d0..e4a83e58057 100644 --- a/docs/clustering.md +++ b/docs/clustering.md @@ -57,9 +57,15 @@ await cluster.sendCommand("key", false, ["SET", "key", "value", "NX"]); // 'OK' await cluster.sendCommand("key", true, ["HGETALL", "key"]); // ['key1', 'field1', 'key2', 'field2'] ``` -## Auth with password and username +## Root nodes vs. defaults -Specifying the password in the URL or a root node will only affect the connection to that specific node. In case you want to set the password for all the connections being created from a cluster instance, use the `defaults` option. +The configuration in `rootNodes` is only used for the connections that discover the cluster topology. It is **not** inherited by the connections the cluster then makes to the discovered nodes — those are created from the `defaults` option (plus the discovered host and port). + +This means that any setting that should apply to every connection in the cluster — credentials, TLS, timeouts, etc. — must be specified via `defaults`, even if it is already present in a root node URL or configuration. + +### Auth with password and username + +Specifying the password in the URL or a root node will only affect the connection used for topology discovery. In case you want to set the password for all the connections being created from a cluster instance, use the `defaults` option. ```javascript createCluster({ @@ -75,6 +81,23 @@ createCluster({ }); ``` +### TLS + +Likewise, TLS options specified in the URL (`rediss://`) or in a root node only affect the topology discovery connection. If your cluster requires TLS (e.g. AWS ElastiCache with in-transit encryption enabled), enable it via `defaults.socket`, otherwise the connections to the discovered nodes will be attempted in plaintext and can hang without an error: + +```javascript +createCluster({ + rootNodes: [{ + url: 'rediss://external-host.io:30001' + }], + defaults: { + socket: { + tls: true + } + } +}); +``` + ## Node Address Map A mapping between the addresses in the cluster (see `CLUSTER SHARDS`) and the addresses the client should connect to. diff --git a/packages/client/lib/cluster/index.ts b/packages/client/lib/cluster/index.ts index 0203f14f209..43e82153847 100644 --- a/packages/client/lib/cluster/index.ts +++ b/packages/client/lib/cluster/index.ts @@ -69,11 +69,18 @@ export interface RedisClusterOptions< /** * Should contain details for some of the cluster nodes that the client will use to discover * the "cluster topology". We recommend including details for at least 3 nodes here. + * + * Note: this configuration is only used for the connections that discover the topology — it is + * not inherited by the connections made to the discovered nodes. Settings that should apply to + * every connection (e.g. credentials, TLS) must be specified via `defaults`. */ rootNodes: Array; /** * Default values used for every client in the cluster. Use this to specify global values, * for example: ACL credentials, timeouts, TLS configuration etc. + * + * The connections to the discovered cluster nodes are created from these defaults (plus the + * discovered host and port) — they do not inherit any other settings from `rootNodes`. */ defaults?: Partial; /** @@ -275,6 +282,24 @@ export default class RedisCluster< }; } + /** + * Creates a new Redis Cluster client. + * + * Note: `rootNodes` is only used to discover the cluster topology; its configuration is not + * inherited by the connections made to the discovered nodes. Any setting that should apply to + * every connection in the cluster (e.g. credentials, TLS) must be specified via `defaults`: + * + * @example + * ```javascript + * createCluster({ + * rootNodes: [{ url: 'rediss://external-host.io:30001' }], + * defaults: { + * password: 'password', + * socket: { tls: true } + * } + * }); + * ``` + */ static create< M extends RedisModules = {}, F extends RedisFunctions = {}, diff --git a/packages/redis/index.ts b/packages/redis/index.ts index b8e78396070..e09af5a694f 100644 --- a/packages/redis/index.ts +++ b/packages/redis/index.ts @@ -97,6 +97,13 @@ export type RedisClusterType< TYPE_MAPPING extends TypeMapping = {} > = genericRedisClusterType; +/** + * Creates a new Redis Cluster client. + * + * Note: `rootNodes` is only used to discover the cluster topology; its configuration is not + * inherited by the connections made to the discovered nodes. Any setting that should apply to + * every connection in the cluster (e.g. credentials, TLS) must be specified via `defaults`. + */ export function createCluster< M extends RedisModules = {}, F extends RedisFunctions = {},