1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-07 13:22:56 +03:00

More fixes for socket issue (#2710)

* more typing fixes

* try to redo typing a bit and genericize to make better

* use genericized cluster options for cluster as well
This commit is contained in:
Shaya Potter
2024-02-21 10:29:24 +02:00
committed by GitHub
parent 7e27f72f72
commit 3e167912fb
6 changed files with 48 additions and 32 deletions

View File

@@ -21,7 +21,8 @@ export interface RedisClientOptions<
F extends RedisFunctions = RedisFunctions, F extends RedisFunctions = RedisFunctions,
S extends RedisScripts = RedisScripts, S extends RedisScripts = RedisScripts,
RESP extends RespVersions = RespVersions, RESP extends RespVersions = RespVersions,
TYPE_MAPPING extends TypeMapping = TypeMapping TYPE_MAPPING extends TypeMapping = TypeMapping,
SocketOptions extends RedisSocketOptions = RedisSocketOptions
> extends CommanderConfig<M, F, S, RESP> { > extends CommanderConfig<M, F, S, RESP> {
/** /**
* `redis[s]://[[username][:password]@][host][:port][/db-number]` * `redis[s]://[[username][:password]@][host][:port][/db-number]`
@@ -31,7 +32,7 @@ export interface RedisClientOptions<
/** /**
* Socket connection properties * Socket connection properties
*/ */
socket?: RedisSocketOptions; socket?: SocketOptions;
/** /**
* ACL username ([see ACL guide](https://redis.io/topics/acl)) * ACL username ([see ACL guide](https://redis.io/topics/acl))
*/ */

View File

@@ -9,25 +9,9 @@ type NetOptions = {
tls?: false; tls?: false;
}; };
type TcpOptions = NetOptions & Omit<
net.TcpNetConnectOpts,
'timeout' | 'onread' | 'readable' | 'writable' | 'port'
> & {
port?: number;
};
type IpcOptions = NetOptions & Omit<
net.IpcNetConnectOpts,
'timeout' | 'onread' | 'readable' | 'writable'
>;
type TlsOptions = {
tls: true;
} & tls.ConnectionOptions;
type ReconnectStrategyFunction = (retries: number, cause: Error) => false | Error | number; type ReconnectStrategyFunction = (retries: number, cause: Error) => false | Error | number;
export type RedisSocketOptions = { type RedisSocketOptionsCommon = {
/** /**
* Connection timeout (in milliseconds) * Connection timeout (in milliseconds)
*/ */
@@ -39,7 +23,30 @@ export type RedisSocketOptions = {
* 3. `(retries: number, cause: Error) => false | number | Error` -> `number` is the same as configuring a `number` directly, `Error` is the same as `false`, but with a custom error. * 3. `(retries: number, cause: Error) => false | number | Error` -> `number` is the same as configuring a `number` directly, `Error` is the same as `false`, but with a custom error.
*/ */
reconnectStrategy?: false | number | ReconnectStrategyFunction; reconnectStrategy?: false | number | ReconnectStrategyFunction;
} & (TcpOptions | IpcOptions | TlsOptions); }
type RedisTcpOptions = RedisSocketOptionsCommon & NetOptions & Omit<
net.TcpNetConnectOpts,
'timeout' | 'onread' | 'readable' | 'writable' | 'port'
> & {
port?: number;
};
type RedisTlsOptions = RedisSocketOptionsCommon & tls.ConnectionOptions & {
tls: true;
host: string;
}
type RedisIpcOptions = RedisSocketOptionsCommon & Omit<
net.IpcNetConnectOpts,
'timeout' | 'onread' | 'readable' | 'writable'
> & {
tls: false;
}
export type RedisTcpSocketOptions = RedisTcpOptions | RedisTlsOptions;
export type RedisSocketOptions = RedisTcpSocketOptions | RedisIpcOptions;
export type RedisSocketInitiator = () => void | Promise<unknown>; export type RedisSocketInitiator = () => void | Promise<unknown>;

View File

@@ -8,6 +8,7 @@ import RedisClusterSlots, { NodeAddressMap, ShardNode } from './cluster-slots';
import RedisClusterMultiCommand, { RedisClusterMultiCommandType } from './multi-command'; import RedisClusterMultiCommand, { RedisClusterMultiCommandType } from './multi-command';
import { PubSubListener } from '../client/pub-sub'; import { PubSubListener } from '../client/pub-sub';
import { ErrorReply } from '../errors'; import { ErrorReply } from '../errors';
import { RedisTcpSocketOptions } from '../client/socket';
interface ClusterCommander< interface ClusterCommander<
M extends RedisModules, M extends RedisModules,
@@ -21,7 +22,7 @@ interface ClusterCommander<
} }
export type RedisClusterClientOptions = Omit< export type RedisClusterClientOptions = Omit<
RedisClientOptions, RedisClientOptions<RedisModules, RedisFunctions, RedisScripts, RespVersions, TypeMapping, RedisTcpSocketOptions>,
keyof ClusterCommander<RedisModules, RedisFunctions, RedisScripts, RespVersions, TypeMapping/*, CommandPolicies*/> keyof ClusterCommander<RedisModules, RedisFunctions, RedisScripts, RespVersions, TypeMapping/*, CommandPolicies*/>
>; >;

View File

@@ -14,6 +14,8 @@ import { setTimeout } from 'node:timers/promises';
import RedisSentinelModule from './module' import RedisSentinelModule from './module'
import { RedisVariadicArgument } from '../commands/generic-transformers'; import { RedisVariadicArgument } from '../commands/generic-transformers';
import { WaitQueue } from './wait-queue'; import { WaitQueue } from './wait-queue';
import { TcpNetConnectOpts } from 'node:net';
import { RedisTcpSocketOptions } from '../client/socket';
interface ClientInfo { interface ClientInfo {
id: number; id: number;
@@ -578,8 +580,8 @@ class RedisSentinelInternal<
} }
readonly #name: string; readonly #name: string;
readonly #nodeClientOptions: RedisClientOptions<M, F, S, RESP, TYPE_MAPPING>; readonly #nodeClientOptions: RedisClientOptions<M, F, S, RESP, TYPE_MAPPING, RedisTcpSocketOptions>;
readonly #sentinelClientOptions: RedisClientOptions<typeof RedisSentinelModule, F, S, RESP, TYPE_MAPPING>; readonly #sentinelClientOptions: RedisClientOptions<typeof RedisSentinelModule, F, S, RESP, TYPE_MAPPING, RedisTcpSocketOptions>;
readonly #scanInterval: number; readonly #scanInterval: number;
readonly #passthroughClientErrorEvents: boolean; readonly #passthroughClientErrorEvents: boolean;
@@ -624,12 +626,12 @@ class RedisSentinelInternal<
this.#scanInterval = options.scanInterval ?? 0; this.#scanInterval = options.scanInterval ?? 0;
this.#passthroughClientErrorEvents = options.passthroughClientErrorEvents ?? false; this.#passthroughClientErrorEvents = options.passthroughClientErrorEvents ?? false;
this.#nodeClientOptions = options.nodeClientOptions ? Object.assign({} as RedisClientOptions<M, F, S, RESP, TYPE_MAPPING>, options.nodeClientOptions) : {}; this.#nodeClientOptions = options.nodeClientOptions ? Object.assign({} as RedisClientOptions<M, F, S, RESP, TYPE_MAPPING, RedisTcpSocketOptions>, options.nodeClientOptions) : {};
if (this.#nodeClientOptions.url !== undefined) { if (this.#nodeClientOptions.url !== undefined) {
throw new Error("invalid nodeClientOptions for Sentinel"); throw new Error("invalid nodeClientOptions for Sentinel");
} }
this.#sentinelClientOptions = options.sentinelClientOptions ? Object.assign({} as RedisClientOptions<typeof RedisSentinelModule, F, S, RESP, TYPE_MAPPING>, options.sentinelClientOptions) : {}; this.#sentinelClientOptions = options.sentinelClientOptions ? Object.assign({} as RedisClientOptions<typeof RedisSentinelModule, F, S, RESP, TYPE_MAPPING, RedisTcpSocketOptions>, options.sentinelClientOptions) : {};
this.#sentinelClientOptions.modules = RedisSentinelModule; this.#sentinelClientOptions.modules = RedisSentinelModule;
if (this.#sentinelClientOptions.url !== undefined) { if (this.#sentinelClientOptions.url !== undefined) {
@@ -754,7 +756,8 @@ class RedisSentinelInternal<
await this.#reset(); await this.#reset();
continue; continue;
} }
this.#trace("attemping to send command to " + client.options?.socket?.host + ":" + client.options?.socket?.port) const sockOpts = client.options?.socket as TcpNetConnectOpts | undefined;
this.#trace("attemping to send command to " + sockOpts?.host + ":" + sockOpts?.port)
try { try {
/* /*
@@ -1198,7 +1201,8 @@ class RedisSentinelInternal<
if (replicaCloseSet.has(str) || !replica.isOpen) { if (replicaCloseSet.has(str) || !replica.isOpen) {
if (replica.isOpen) { if (replica.isOpen) {
this.#trace(`destroying replica client to ${replica.options?.socket?.host}:${replica.options?.socket?.port}`); const sockOpts = replica.options?.socket as TcpNetConnectOpts | undefined;
this.#trace(`destroying replica client to ${sockOpts?.host}:${sockOpts?.port}`);
replica.destroy() replica.destroy()
} }
if (!removedSet.has(str)) { if (!removedSet.has(str)) {

View File

@@ -3,6 +3,7 @@ import { CommandOptions } from '../client/commands-queue';
import { CommandSignature, CommanderConfig, RedisFunctions, RedisModules, RedisScripts, RespVersions, TypeMapping } from '../RESP/types'; import { CommandSignature, CommanderConfig, RedisFunctions, RedisModules, RedisScripts, RespVersions, TypeMapping } from '../RESP/types';
import COMMANDS from '../commands'; import COMMANDS from '../commands';
import RedisSentinel, { RedisSentinelClient } from '.'; import RedisSentinel, { RedisSentinelClient } from '.';
import { RedisTcpSocketOptions } from '../client/socket';
export interface RedisNode { export interface RedisNode {
host: string; host: string;
@@ -31,11 +32,11 @@ export interface RedisSentinelOptions<
/** /**
* The configuration values for every node in the cluster. Use this for example when specifying an ACL user to connect with * The configuration values for every node in the cluster. Use this for example when specifying an ACL user to connect with
*/ */
nodeClientOptions?: RedisClientOptions<M, F, S, RESP, TYPE_MAPPING>; nodeClientOptions?: RedisClientOptions<M, F, S, RESP, TYPE_MAPPING, RedisTcpSocketOptions>;
/** /**
* The configuration values for every sentinel in the cluster. Use this for example when specifying an ACL user to connect with * The configuration values for every sentinel in the cluster. Use this for example when specifying an ACL user to connect with
*/ */
sentinelClientOptions?: RedisClientOptions<M, F, S, RESP, TYPE_MAPPING>; sentinelClientOptions?: RedisClientOptions<M, F, S, RESP, TYPE_MAPPING, RedisTcpSocketOptions>;
/** /**
* The number of clients connected to the master node * The number of clients connected to the master node
*/ */

View File

@@ -1,5 +1,5 @@
import { Command, RedisFunction, RedisScript, RespVersions } from '../RESP/types'; import { Command, RedisFunction, RedisScript, RespVersions } from '../RESP/types';
import { RedisSocketOptions } from '../client/socket'; import { RedisSocketOptions, RedisTcpSocketOptions } from '../client/socket';
import { functionArgumentsPrefix, getTransformReply, scriptArgumentsPrefix } from '../commander'; import { functionArgumentsPrefix, getTransformReply, scriptArgumentsPrefix } from '../commander';
import { NamespaceProxySentinel, NamespaceProxySentinelClient, NodeInfo, ProxySentinel, ProxySentinelClient, RedisNode } from './types'; import { NamespaceProxySentinel, NamespaceProxySentinelClient, NodeInfo, ProxySentinel, ProxySentinelClient, RedisNode } from './types';
@@ -27,9 +27,11 @@ export function createNodeList(nodes: Array<NodeInfo>) {
} }
export function clientSocketToNode(socket: RedisSocketOptions): RedisNode { export function clientSocketToNode(socket: RedisSocketOptions): RedisNode {
const s = socket as RedisTcpSocketOptions;
return { return {
host: socket.host!, host: s.host!,
port: socket.port! port: s.port!
} }
} }