You've already forked node-redis
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:
@@ -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))
|
||||||
*/
|
*/
|
||||||
|
@@ -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>;
|
||||||
|
|
||||||
|
@@ -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*/>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
@@ -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)) {
|
||||||
|
@@ -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
|
||||||
*/
|
*/
|
||||||
|
@@ -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!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user