From cc83cee22ce5cc835d54ea2281c5debb2e6cd3ff Mon Sep 17 00:00:00 2001 From: leibale Date: Thu, 7 Oct 2021 10:20:21 -0400 Subject: [PATCH] fix #1671 - add support for all client configurations in cluster --- README.md | 34 +++++++++++++++------------------- index.ts | 2 -- lib/cluster-slots.ts | 12 +++++------- lib/cluster.spec.ts | 4 ++-- lib/cluster.ts | 10 ++++++---- lib/commands/BZPOPMAX.spec.ts | 1 - lib/test-utils.ts | 22 +++++++++++++--------- 7 files changed, 41 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index c5f0ea1a1c..c768b691d7 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ The above code connects to localhost on port 6379. To connect to a different hos ```typescript createClient({ - url: 'redis://alice:foobared@awesome.redis.server:6380', + url: 'redis://alice:foobared@awesome.redis.server:6380' }); ``` @@ -78,7 +78,7 @@ Modifiers to commands are specified using a JavaScript object: ```typescript await client.set('key', 'value', { EX: 10, - NX: true, + NX: true }); ``` @@ -181,12 +181,9 @@ for await (const key of client.scanIterator()) { This works with `HSCAN`, `SSCAN`, and `ZSCAN` too: ```typescript -for await (const member of client.hScanIterator('hash')) { -} -for await (const { field, value } of client.sScanIterator('set')) { -} -for await (const { member, score } of client.zScanIterator('sorted-set')) { -} +for await (const member of client.hScanIterator('hash')) {} +for await (const { field, value } of client.sScanIterator('set')) {} +for await (const { member, score } of client.zScanIterator('sorted-set')) {} ``` You can override the default options by providing a configuration object: @@ -204,7 +201,8 @@ client.scanIterator({ Define new functions using [Lua scripts](https://redis.io/commands/eval) which execute on the Redis server: ```typescript -import { createClient, defineScript } from 'redis'; +import { createClient } from 'redis'; +import { defineScript } from 'redis/lua-script'; (async () => { const client = createClient({ @@ -218,9 +216,9 @@ import { createClient, defineScript } from 'redis'; }, transformReply(reply: number): number { return reply; - }, - }), - }, + } + }) + } }); await client.connect(); @@ -241,14 +239,12 @@ import { createCluster } from 'redis'; const cluster = createCluster({ rootNodes: [ { - host: '10.0.0.1', - port: 30001, + url: 'redis://10.0.0.1:30001' }, { - host: '10.0.0.2', - port: 30002, - }, - ], + url: 'redis://10.0.0.2:30002' + } + ] }); cluster.on('error', (err) => console.log('Redis Cluster Error', err)); @@ -274,7 +270,7 @@ Of course, if you don't do something with your Promises you're certain to get [u ```typescript await Promise.all([ client.set('Tm9kZSBSZWRpcw==', 'users:1'), - client.sAdd('users:1:tokens', 'Tm9kZSBSZWRpcw=='), + client.sAdd('users:1:tokens', 'Tm9kZSBSZWRpcw==') ]); ``` diff --git a/index.ts b/index.ts index 408cbe3b99..fb448f989c 100644 --- a/index.ts +++ b/index.ts @@ -6,5 +6,3 @@ export const createClient = RedisClient.create; export const commandOptions = RedisClient.commandOptions; export const createCluster = RedisCluster.create; - -export { defineScript } from './lib/lua-script'; diff --git a/lib/cluster-slots.ts b/lib/cluster-slots.ts index a5155cc53d..4c33f2e0f7 100644 --- a/lib/cluster-slots.ts +++ b/lib/cluster-slots.ts @@ -2,7 +2,7 @@ import calculateSlot from 'cluster-key-slot'; import RedisClient, { RedisClientType } from './client'; import { RedisSocketOptions } from './socket'; import { RedisClusterMasterNode, RedisClusterReplicaNode } from './commands/CLUSTER_NODES'; -import { RedisClusterOptions } from './cluster'; +import { RedisClusterClientOptions, RedisClusterOptions } from './cluster'; import { RedisModules } from './commands'; import { RedisLuaScripts } from './lua-script'; @@ -39,21 +39,19 @@ export default class RedisClusterSlots): Promise { - if (await this.#discoverNodes(startWith.options?.socket)) return; + if (await this.#discoverNodes(startWith.options)) return; for (const { client } of this.#nodeByUrl.values()) { if (client === startWith) continue; - if (await this.#discoverNodes(client.options?.socket)) return; + if (await this.#discoverNodes(client.options)) return; } throw new Error('None of the cluster nodes is available'); } - async #discoverNodes(socketOptions?: RedisSocketOptions): Promise { - const client = RedisClient.create({ - socket: socketOptions - }); + async #discoverNodes(clientOptions?: RedisClusterClientOptions): Promise { + const client = RedisClient.create(clientOptions); await client.connect(); diff --git a/lib/cluster.spec.ts b/lib/cluster.spec.ts index b7dbe50c90..22ae204f9a 100644 --- a/lib/cluster.spec.ts +++ b/lib/cluster.spec.ts @@ -8,7 +8,7 @@ import { ClusterSlotStates } from './commands/CLUSTER_SETSLOT'; describe('Cluster', () => { it('sendCommand', async () => { const cluster = RedisCluster.create({ - rootNodes: TEST_REDIS_CLUSTERES[TestRedisClusters.OPEN], + ...TEST_REDIS_CLUSTERES[TestRedisClusters.OPEN], useReplicas: true }); @@ -42,7 +42,7 @@ describe('Cluster', () => { it('scripts', async () => { const cluster = RedisCluster.create({ - rootNodes: TEST_REDIS_CLUSTERES[TestRedisClusters.OPEN], + ...TEST_REDIS_CLUSTERES[TestRedisClusters.OPEN], scripts: { add: defineScript({ NUMBER_OF_KEYS: 0, diff --git a/lib/cluster.ts b/lib/cluster.ts index 87dcec17b7..565bb859b8 100644 --- a/lib/cluster.ts +++ b/lib/cluster.ts @@ -1,14 +1,16 @@ import { RedisCommand, RedisCommandReply, RedisModules, TransformArgumentsReply } from './commands'; -import RedisClient, { ClientCommandOptions, RedisClientType, WithPlugins } from './client'; -import { RedisSocketOptions } from './socket'; +import RedisClient, { ClientCommandOptions, RedisClientOptions, RedisClientType, WithPlugins } from './client'; import RedisClusterSlots, { ClusterNode } from './cluster-slots'; import { RedisLuaScript, RedisLuaScripts } from './lua-script'; import { extendWithModulesAndScripts, extendWithDefaultCommands, transformCommandArguments, transformCommandReply } from './commander'; import RedisMultiCommand, { MultiQueuedCommand, RedisMultiCommandType } from './multi-command'; import { EventEmitter } from 'events'; -export interface RedisClusterOptions { - rootNodes: Array; +export type RedisClusterClientOptions = Omit, 'modules' | 'scripts'>; + +export interface RedisClusterOptions { + rootNodes: Array; + defaults?: RedisClusterClientOptions; modules?: M; scripts?: S; useReplicas?: boolean; diff --git a/lib/commands/BZPOPMAX.spec.ts b/lib/commands/BZPOPMAX.spec.ts index c4bcc321b2..090dfba096 100644 --- a/lib/commands/BZPOPMAX.spec.ts +++ b/lib/commands/BZPOPMAX.spec.ts @@ -2,7 +2,6 @@ import { strict as assert } from 'assert'; import { TestRedisServers, itWithClient } from '../test-utils'; import { transformArguments, transformReply } from './BZPOPMAX'; import { commandOptions } from '../../index'; -import { describe } from 'mocha'; describe('BZPOPMAX', () => { describe('transformArguments', () => { diff --git a/lib/test-utils.ts b/lib/test-utils.ts index 713a1a3434..bc3c051460 100644 --- a/lib/test-utils.ts +++ b/lib/test-utils.ts @@ -5,7 +5,7 @@ import { once } from 'events'; import { RedisSocketOptions } from './socket'; import which from 'which'; import { SinonSpy } from 'sinon'; -import RedisCluster, { RedisClusterType } from './cluster'; +import RedisCluster, { RedisClusterOptions, RedisClusterType } from './cluster'; import { promises as fs } from 'fs'; import { Context as MochaContext } from 'mocha'; import { promiseTimeout } from './utils'; @@ -60,7 +60,7 @@ export enum TestRedisClusters { OPEN } -export const TEST_REDIS_CLUSTERES: Record> = {}; +export const TEST_REDIS_CLUSTERES: Record> = {}; let port = 6379; @@ -248,9 +248,13 @@ async function spawnPasswordServer(): Promise { } async function spawnOpenCluster(): Promise { - TEST_REDIS_CLUSTERES[TestRedisClusters.OPEN] = (await spawnGlobalRedisCluster(TestRedisClusters.OPEN, 3)).map(port => ({ - port - })); + TEST_REDIS_CLUSTERES[TestRedisClusters.OPEN] = { + rootNodes: (await spawnGlobalRedisCluster(TestRedisClusters.OPEN, 3)).map(port => ({ + socket: { + port + } + })) + }; } before(function () { @@ -314,9 +318,7 @@ export function itWithCluster( it(title, async function () { if (handleMinimumRedisVersion(this, options?.minimumRedisVersion)) return; - const cluster = RedisCluster.create({ - rootNodes: TEST_REDIS_CLUSTERES[type] - }); + const cluster = RedisCluster.create(TEST_REDIS_CLUSTERES[type]); await cluster.connect(); @@ -337,7 +339,9 @@ export function itWithDedicatedCluster(title: string, fn: (cluster: RedisCluster const spawnResults = await spawnRedisCluster(null, 3), cluster = RedisCluster.create({ rootNodes: [{ - port: spawnResults[0].port + socket: { + port: spawnResults[0].port + } }] });