mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
feat(microservices): migrate redis transporter to internally use ioredis package
This commit is contained in:
@@ -34,7 +34,7 @@ describe('Disconnected client', () => {
|
||||
.send({
|
||||
transport: Transport.REDIS,
|
||||
options: {
|
||||
url: 'redis://localhost:3333',
|
||||
port: '3333',
|
||||
},
|
||||
})
|
||||
.expect(408);
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
Controller,
|
||||
InternalServerErrorException,
|
||||
Post,
|
||||
RequestTimeoutException,
|
||||
RequestTimeoutException
|
||||
} from '@nestjs/common';
|
||||
import { ClientProxyFactory } from '@nestjs/microservices';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
@@ -24,7 +24,8 @@ export class DisconnectedClientController {
|
||||
return throwError(() =>
|
||||
code === 'ECONNREFUSED' ||
|
||||
code === 'CONN_ERR' ||
|
||||
code === 'CONNECTION_REFUSED'
|
||||
code === 'CONNECTION_REFUSED' ||
|
||||
error.message === 'Connection is closed.'
|
||||
? new RequestTimeoutException('ECONNREFUSED')
|
||||
: new InternalServerErrorException(),
|
||||
);
|
||||
|
||||
73
package-lock.json
generated
73
package-lock.json
generated
@@ -1707,6 +1707,12 @@
|
||||
"integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@ioredis/commands": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.1.1.tgz",
|
||||
"integrity": "sha512-fsR4P/ROllzf/7lXYyElUJCheWdTJVJvOTps8v9IWKFATxR61ANOlnoPqhH099xYLrJGpc2ZQ28B3rMeUt5VQg==",
|
||||
"dev": true
|
||||
},
|
||||
"@istanbuljs/load-nyc-config": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
|
||||
@@ -2993,15 +2999,6 @@
|
||||
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/redis": {
|
||||
"version": "4.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/redis/-/redis-4.0.11.tgz",
|
||||
"integrity": "sha512-bI+gth8La8Wg/QCR1+V1fhrL9+LZUSWfcqpOj2Kc80ZQ4ffbdL173vQd5wovmoV9i071FU9oP2g6etLuEwb6Rg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"redis": "*"
|
||||
}
|
||||
},
|
||||
"@types/reflect-metadata": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/reflect-metadata/-/reflect-metadata-0.1.0.tgz",
|
||||
@@ -6062,6 +6059,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"cluster-key-slot": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz",
|
||||
"integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==",
|
||||
"dev": true
|
||||
},
|
||||
"code-block-writer": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-11.0.0.tgz",
|
||||
@@ -13150,6 +13153,46 @@
|
||||
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
|
||||
"dev": true
|
||||
},
|
||||
"ioredis": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.0.4.tgz",
|
||||
"integrity": "sha512-qFJw3MnPNsJF1lcIOP3vztbsasOXK3nDdNAgjQj7t7/Bn/w10PGchTOpqylQNxjzPbLoYDu34LjeJtSWiKBntQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ioredis/commands": "^1.1.1",
|
||||
"cluster-key-slot": "^1.1.0",
|
||||
"debug": "^4.3.4",
|
||||
"denque": "^2.0.1",
|
||||
"lodash.defaults": "^4.2.0",
|
||||
"lodash.isarguments": "^3.1.0",
|
||||
"redis-errors": "^1.2.0",
|
||||
"redis-parser": "^3.0.0",
|
||||
"standard-as-callback": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"denque": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz",
|
||||
"integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"ip": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
||||
@@ -15121,6 +15164,12 @@
|
||||
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.defaults": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||
"integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.escape": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
|
||||
@@ -20699,6 +20748,12 @@
|
||||
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=",
|
||||
"dev": true
|
||||
},
|
||||
"standard-as-callback": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
||||
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
|
||||
"dev": true
|
||||
},
|
||||
"static-eval": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz",
|
||||
|
||||
11
package.json
11
package.json
@@ -72,6 +72,10 @@
|
||||
"@codechecks/client": "0.1.12",
|
||||
"@commitlint/cli": "17.0.0",
|
||||
"@commitlint/config-angular": "17.0.0",
|
||||
"@fastify/cors": "7.0.0",
|
||||
"@fastify/formbody": "6.0.0",
|
||||
"@fastify/multipart": "6.0.0",
|
||||
"@fastify/static": "5.0.0",
|
||||
"@grpc/grpc-js": "1.6.7",
|
||||
"@grpc/proto-loader": "0.6.12",
|
||||
"@nestjs/apollo": "10.0.11",
|
||||
@@ -89,7 +93,6 @@
|
||||
"@types/http-errors": "1.8.2",
|
||||
"@types/mocha": "9.1.1",
|
||||
"@types/node": "17.0.34",
|
||||
"@types/redis": "4.0.11",
|
||||
"@types/reflect-metadata": "0.1.0",
|
||||
"@types/sinon": "10.0.11",
|
||||
"@types/socket.io": "3.0.2",
|
||||
@@ -122,10 +125,6 @@
|
||||
"eventsource": "2.0.2",
|
||||
"fancy-log": "2.0.0",
|
||||
"fastify": "3.29.0",
|
||||
"@fastify/cors": "7.0.0",
|
||||
"@fastify/formbody": "6.0.0",
|
||||
"@fastify/multipart": "6.0.0",
|
||||
"@fastify/static": "5.0.0",
|
||||
"graphql": "15.8.0",
|
||||
"graphql-tools": "8.2.9",
|
||||
"gulp": "4.0.2",
|
||||
@@ -137,6 +136,7 @@
|
||||
"http-errors": "2.0.0",
|
||||
"husky": "8.0.1",
|
||||
"imports-loader": "3.1.1",
|
||||
"ioredis": "5.0.4",
|
||||
"json-loader": "0.5.7",
|
||||
"kafkajs": "2.0.0",
|
||||
"lerna": "3.0.0",
|
||||
@@ -156,7 +156,6 @@
|
||||
"nyc": "15.1.0",
|
||||
"point-of-view": "5.3.0",
|
||||
"prettier": "2.6.2",
|
||||
"redis": "3.1.2",
|
||||
"rxjs-compat": "6.6.7",
|
||||
"sinon": "14.0.0",
|
||||
"sinon-chai": "3.7.0",
|
||||
|
||||
@@ -1,48 +1,31 @@
|
||||
import { Logger } from '@nestjs/common/services/logger.service';
|
||||
import { loadPackage } from '@nestjs/common/utils/load-package.util';
|
||||
import {
|
||||
EmptyError,
|
||||
fromEvent,
|
||||
lastValueFrom,
|
||||
merge,
|
||||
Subject,
|
||||
zip,
|
||||
} from 'rxjs';
|
||||
import { share, take, tap } from 'rxjs/operators';
|
||||
import {
|
||||
CONNECT_EVENT,
|
||||
ECONNREFUSED,
|
||||
ERROR_EVENT,
|
||||
MESSAGE_EVENT,
|
||||
REDIS_DEFAULT_URL,
|
||||
REDIS_DEFAULT_HOST,
|
||||
REDIS_DEFAULT_PORT,
|
||||
} from '../constants';
|
||||
import {
|
||||
ClientOpts,
|
||||
RedisClient,
|
||||
RetryStrategyOptions,
|
||||
} from '../external/redis.interface';
|
||||
import { ReadPacket, RedisOptions, WritePacket } from '../interfaces';
|
||||
import { ClientProxy } from './client-proxy';
|
||||
|
||||
let redisPackage: any = {};
|
||||
type Redis = any;
|
||||
|
||||
let redisPackage = {} as any;
|
||||
|
||||
export class ClientRedis extends ClientProxy {
|
||||
protected readonly logger = new Logger(ClientProxy.name);
|
||||
protected readonly subscriptionsCount = new Map<string, number>();
|
||||
protected readonly url: string;
|
||||
protected pubClient: RedisClient;
|
||||
protected subClient: RedisClient;
|
||||
protected pubClient: Redis;
|
||||
protected subClient: Redis;
|
||||
protected connection: Promise<any>;
|
||||
protected isExplicitlyTerminated = false;
|
||||
|
||||
constructor(protected readonly options: RedisOptions['options']) {
|
||||
super();
|
||||
this.url =
|
||||
this.getOptionsProp(options, 'url') ||
|
||||
(!this.getOptionsProp(options, 'host') && REDIS_DEFAULT_URL);
|
||||
|
||||
redisPackage = loadPackage('redis', ClientRedis.name, () =>
|
||||
require('redis'),
|
||||
redisPackage = loadPackage('ioredis', ClientRedis.name, () =>
|
||||
require('ioredis'),
|
||||
);
|
||||
|
||||
this.initializeSerializer(options);
|
||||
@@ -64,73 +47,57 @@ export class ClientRedis extends ClientProxy {
|
||||
this.isExplicitlyTerminated = true;
|
||||
}
|
||||
|
||||
public connect(): Promise<any> {
|
||||
public async connect(): Promise<any> {
|
||||
if (this.pubClient && this.subClient) {
|
||||
return this.connection;
|
||||
}
|
||||
const error$ = new Subject<Error>();
|
||||
|
||||
this.pubClient = this.createClient(error$);
|
||||
this.subClient = this.createClient(error$);
|
||||
this.pubClient = this.createClient();
|
||||
this.subClient = this.createClient();
|
||||
this.handleError(this.pubClient);
|
||||
this.handleError(this.subClient);
|
||||
|
||||
const pubConnect$ = fromEvent(this.pubClient, CONNECT_EVENT);
|
||||
const subClient$ = fromEvent(this.subClient, CONNECT_EVENT);
|
||||
this.connection = Promise.all([
|
||||
this.subClient.connect(),
|
||||
this.pubClient.connect(),
|
||||
]);
|
||||
await this.connection;
|
||||
|
||||
this.connection = lastValueFrom(
|
||||
merge(error$, zip(pubConnect$, subClient$)).pipe(
|
||||
take(1),
|
||||
tap(() =>
|
||||
this.subClient.on(MESSAGE_EVENT, this.createResponseCallback()),
|
||||
),
|
||||
share(),
|
||||
),
|
||||
).catch(err => {
|
||||
if (err instanceof EmptyError) {
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
this.subClient.on(MESSAGE_EVENT, this.createResponseCallback());
|
||||
return this.connection;
|
||||
}
|
||||
|
||||
public createClient(error$: Subject<Error>): RedisClient {
|
||||
return redisPackage.createClient({
|
||||
...this.getClientOptions(error$),
|
||||
url: this.url,
|
||||
public createClient(): Redis {
|
||||
return new redisPackage({
|
||||
host: REDIS_DEFAULT_HOST,
|
||||
port: REDIS_DEFAULT_PORT,
|
||||
...this.getClientOptions(),
|
||||
lazyConnect: true,
|
||||
});
|
||||
}
|
||||
|
||||
public handleError(client: RedisClient) {
|
||||
public handleError(client: Redis) {
|
||||
client.addListener(ERROR_EVENT, (err: any) => this.logger.error(err));
|
||||
}
|
||||
|
||||
public getClientOptions(error$: Subject<Error>): Partial<ClientOpts> {
|
||||
const retry_strategy = (options: RetryStrategyOptions) =>
|
||||
this.createRetryStrategy(options, error$);
|
||||
public getClientOptions(): Partial<RedisOptions['options']> {
|
||||
const retryStrategy = (times: number) => this.createRetryStrategy(times);
|
||||
|
||||
return {
|
||||
...(this.options || {}),
|
||||
retry_strategy,
|
||||
retryStrategy,
|
||||
};
|
||||
}
|
||||
|
||||
public createRetryStrategy(
|
||||
options: RetryStrategyOptions,
|
||||
error$: Subject<Error>,
|
||||
): undefined | number | Error {
|
||||
if (options.error && (options.error as any).code === ECONNREFUSED) {
|
||||
error$.error(options.error);
|
||||
}
|
||||
public createRetryStrategy(times: number): undefined | number {
|
||||
if (this.isExplicitlyTerminated) {
|
||||
return undefined;
|
||||
}
|
||||
if (
|
||||
!this.getOptionsProp(this.options, 'retryAttempts') ||
|
||||
options.attempt > this.getOptionsProp(this.options, 'retryAttempts')
|
||||
times > this.getOptionsProp(this.options, 'retryAttempts')
|
||||
) {
|
||||
return new Error('Retry time exhausted');
|
||||
this.logger.error('Retry time exhausted');
|
||||
return;
|
||||
}
|
||||
return this.getOptionsProp(this.options, 'retryDelay') || 0;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ import { ROUTE_ARGS_METADATA } from '@nestjs/common/constants';
|
||||
|
||||
export const TCP_DEFAULT_PORT = 3000;
|
||||
export const TCP_DEFAULT_HOST = 'localhost';
|
||||
export const REDIS_DEFAULT_URL = 'redis://localhost:6379';
|
||||
|
||||
export const REDIS_DEFAULT_PORT = 6379;
|
||||
export const REDIS_DEFAULT_HOST = 'localhost';
|
||||
|
||||
export const NATS_DEFAULT_URL = 'nats://localhost:4222';
|
||||
export const MQTT_DEFAULT_URL = 'mqtt://localhost:1883';
|
||||
export const GRPC_DEFAULT_URL = 'localhost:5000';
|
||||
|
||||
532
packages/microservices/external/redis.interface.ts
vendored
532
packages/microservices/external/redis.interface.ts
vendored
@@ -1,383 +1,167 @@
|
||||
/* eslint-disable @typescript-eslint/adjacent-overload-signatures */
|
||||
|
||||
export interface RetryStrategyOptions {
|
||||
error: Error;
|
||||
total_retry_time: number;
|
||||
times_connected: number;
|
||||
attempt: number;
|
||||
}
|
||||
|
||||
export interface ClientOpts {
|
||||
auth_pass?: string;
|
||||
command_queue_high_water?: number;
|
||||
command_queue_low_water?: number;
|
||||
connect_timeout?: number;
|
||||
db?: string;
|
||||
detect_buffers?: boolean;
|
||||
disable_resubscribing?: boolean;
|
||||
enable_offline_queue?: boolean;
|
||||
family?: string;
|
||||
host?: string;
|
||||
max_attempts?: number;
|
||||
no_ready_check?: boolean;
|
||||
parser?: string;
|
||||
password?: string;
|
||||
path?: string;
|
||||
port?: number;
|
||||
prefix?: string;
|
||||
rename_commands?: any;
|
||||
retry_max_delay?: number;
|
||||
retry_strategy?: any;
|
||||
retry_unfulfilled_commands?: boolean;
|
||||
return_buffers?: boolean;
|
||||
socket_keepalive?: boolean;
|
||||
socket_nodelay?: boolean;
|
||||
string_numbers?: boolean;
|
||||
tls?: any;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export interface RedisClient {
|
||||
// event: connect
|
||||
// event: error
|
||||
// event: message
|
||||
// event: pmessage
|
||||
// event: subscribe
|
||||
// event: psubscribe
|
||||
// event: unsubscribe
|
||||
// event: punsubscribe
|
||||
|
||||
connected: boolean;
|
||||
retry_delay: number;
|
||||
retry_backoff: number;
|
||||
command_queue: any[];
|
||||
offline_queue: any[];
|
||||
server_info: any;
|
||||
|
||||
/**
|
||||
* @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/ioredis/index.d.ts
|
||||
*/
|
||||
export interface IORedisOptions {
|
||||
port?: number | undefined;
|
||||
host?: string | undefined;
|
||||
/**
|
||||
* Forcibly close the connection to the Redis server. Note that this does not wait until all replies have been parsed. If you want to exit cleanly, call client.quit()
|
||||
* 4 (IPv4) or 6 (IPv6), Defaults to 4.
|
||||
*/
|
||||
family?: number | undefined;
|
||||
/**
|
||||
* Local domain socket path. If set the port, host and family will be ignored.
|
||||
*/
|
||||
path?: string | undefined;
|
||||
/**
|
||||
* TCP KeepAlive on the socket with a X ms delay before start. Set to a non-number value to disable keepAlive.
|
||||
*/
|
||||
keepAlive?: number | undefined;
|
||||
/**
|
||||
* Whether to disable the Nagle's Algorithm.
|
||||
*/
|
||||
noDelay?: boolean | undefined;
|
||||
/**
|
||||
* Force numbers to be always returned as JavaScript strings. This option is necessary when dealing with big numbers (exceed the [-2^53, +2^53] range).
|
||||
*/
|
||||
stringNumbers?: boolean | undefined;
|
||||
/**
|
||||
* Default script definition caching time.
|
||||
*/
|
||||
maxScriptsCachingTime?: number | undefined;
|
||||
connectionName?: string | undefined;
|
||||
/**
|
||||
* If set, client will send AUTH command with the value of this option as the first argument when connected. The `password` option must be set too. Username should only be set for Redis >=6.
|
||||
*/
|
||||
username?: string | undefined;
|
||||
/**
|
||||
* If set, client will send AUTH command with the value of this option when connected.
|
||||
*/
|
||||
password?: string | undefined;
|
||||
/**
|
||||
* Database index to use.
|
||||
*/
|
||||
db?: number | undefined;
|
||||
/**
|
||||
* When a connection is established to the Redis server, the server might still be loading
|
||||
* the database from disk. While loading, the server not respond to any commands.
|
||||
* To work around this, when this option is true, ioredis will check the status of the Redis server,
|
||||
* and when the Redis server is able to process commands, a ready event will be emitted.
|
||||
*/
|
||||
enableReadyCheck?: boolean | undefined;
|
||||
keyPrefix?: string | undefined;
|
||||
/**
|
||||
* When the return value isn't a number, ioredis will stop trying to reconnect.
|
||||
* Fixed in: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/15858
|
||||
*/
|
||||
retryStrategy?(times: number): number | void | null;
|
||||
/**
|
||||
* By default, all pending commands will be flushed with an error every
|
||||
* 20 retry attempts. That makes sure commands won't wait forever when
|
||||
* the connection is down. You can change this behavior by setting
|
||||
* `maxRetriesPerRequest`.
|
||||
*
|
||||
* @param {boolean} flush You should set flush to true, if you are not absolutely sure you do not care about any other commands. If you set flush to false all still running commands will silently fail.
|
||||
* Set maxRetriesPerRequest to `null` to disable this behavior, and
|
||||
* every command will wait forever until the connection is alive again
|
||||
* (which is the default behavior before ioredis v4).
|
||||
*/
|
||||
end(flush: boolean): void;
|
||||
unref(): void;
|
||||
|
||||
maxRetriesPerRequest?: number | null | undefined;
|
||||
/**
|
||||
* Stop sending commands and queue the commands.
|
||||
* The milliseconds before a timeout occurs when executing a single
|
||||
* command. By default, there is no timeout and the client will wait
|
||||
* indefinitely. The timeout is enforced only on the client side, not
|
||||
* server side. The server may still complete the operation after a
|
||||
* timeout error occurs on the client side.
|
||||
*/
|
||||
cork(): void;
|
||||
|
||||
commandTimeout?: number | undefined;
|
||||
/**
|
||||
* Resume and send the queued commands at once.
|
||||
* 1/true means reconnect, 2 means reconnect and resend failed command. Returning false will ignore
|
||||
* the error and do nothing.
|
||||
*/
|
||||
uncork(): void;
|
||||
|
||||
// Low level command execution
|
||||
send_command(command: string, ...args: any[]): boolean;
|
||||
|
||||
// Connection (http://redis.io/commands#connection)
|
||||
auth(password: string, callback?: any): boolean;
|
||||
ping(callback?: any): boolean;
|
||||
|
||||
// Strings (http://redis.io/commands#strings)
|
||||
append(key: string, value: string, callback?: any): boolean;
|
||||
bitcount(key: string, callback?: any): boolean;
|
||||
bitcount(key: string, start: number, end: number, callback?: any): boolean;
|
||||
set(key: string, value: string, callback?: any): boolean;
|
||||
get(key: string, callback?: any): boolean;
|
||||
exists(key: string, value: string, callback?: any): boolean;
|
||||
|
||||
publish(channel: string, value: any): boolean;
|
||||
subscribe(channel: string): boolean;
|
||||
on(event: string, callback: Function): any;
|
||||
off(event: string, callback: Function): any;
|
||||
addListener(event: string, callback: Function): any;
|
||||
|
||||
/*
|
||||
commands = set_union([
|
||||
"get", "set", "setnx", "setex", "append", "strlen", "del", "exists", "setbit", "getbit", "setrange", "getrange", "substr",
|
||||
"incr", "decr", "mget", "rpush", "lpush", "rpushx", "lpushx", "linsert", "rpop", "lpop", "brpop", "brpoplpush", "blpop", "llen", "lindex",
|
||||
"lset", "lrange", "ltrim", "lrem", "rpoplpush", "sadd", "srem", "smove", "sismember", "scard", "spop", "srandmember", "sinter", "sinterstore",
|
||||
"sunion", "sunionstore", "sdiff", "sdiffstore", "smembers", "zadd", "zincrby", "zrem", "zremrangebyscore", "zremrangebyrank", "zunionstore",
|
||||
"zinterstore", "zrange", "zrangebyscore", "zrevrangebyscore", "zcount", "zrevrange", "zcard", "zscore", "zrank", "zrevrank", "hset", "hsetnx",
|
||||
"hget", "hmset", "hmget", "hincrby", "hincrbyfloat", "hdel", "hlen", "hkeys", "hvals", "hgetall", "hexists", "incrby", "decrby", "getset", "mset", "msetnx",
|
||||
"randomkey", "select", "move", "rename", "renamenx", "expire", "expireat", "keys", "dbsize", "auth", "ping", "echo", "save", "bgsave",
|
||||
"bgrewriteaof", "shutdown", "lastsave", "type", "any", "exec", "discard", "sync", "flushdb", "flushall", "sort", "info", "monitor", "ttl",
|
||||
"persist", "slaveof", "debug", "config", "subscribe", "unsubscribe", "psubscribe", "punsubscribe", "publish", "watch", "unwatch", "cluster",
|
||||
"restore", "migrate", "dump", "object", "client", "eval", "evalsha"], require("./lib/commands"));
|
||||
reconnectOnError?(error: Error): boolean | 1 | 2;
|
||||
/**
|
||||
* By default, if there is no active connection to the Redis server, commands are added to a queue
|
||||
* and are executed once the connection is "ready" (when enableReadyCheck is true, "ready" means
|
||||
* the Redis server has loaded the database from disk, otherwise means the connection to the Redis
|
||||
* server has been established). If this option is false, when execute the command when the connection
|
||||
* isn't ready, an error will be returned.
|
||||
*/
|
||||
|
||||
get(args: any[], callback?: any): boolean;
|
||||
get(...args: any[]): boolean;
|
||||
set(args: any[], callback?: any): boolean;
|
||||
set(...args: any[]): boolean;
|
||||
setnx(args: any[], callback?: any): boolean;
|
||||
setnx(...args: any[]): boolean;
|
||||
setex(args: any[], callback?: any): boolean;
|
||||
setex(...args: any[]): boolean;
|
||||
append(args: any[], callback?: any): boolean;
|
||||
append(...args: any[]): boolean;
|
||||
strlen(args: any[], callback?: any): boolean;
|
||||
strlen(...args: any[]): boolean;
|
||||
del(args: any[], callback?: any): boolean;
|
||||
del(...args: any[]): boolean;
|
||||
exists(args: any[], callback?: any): boolean;
|
||||
exists(...args: any[]): boolean;
|
||||
setbit(args: any[], callback?: any): boolean;
|
||||
setbit(...args: any[]): boolean;
|
||||
getbit(args: any[], callback?: any): boolean;
|
||||
getbit(...args: any[]): boolean;
|
||||
setrange(args: any[], callback?: any): boolean;
|
||||
setrange(...args: any[]): boolean;
|
||||
getrange(args: any[], callback?: any): boolean;
|
||||
getrange(...args: any[]): boolean;
|
||||
substr(args: any[], callback?: any): boolean;
|
||||
substr(...args: any[]): boolean;
|
||||
incr(args: any[], callback?: any): boolean;
|
||||
incr(...args: any[]): boolean;
|
||||
decr(args: any[], callback?: any): boolean;
|
||||
decr(...args: any[]): boolean;
|
||||
mget(args: any[], callback?: any): boolean;
|
||||
mget(...args: any[]): boolean;
|
||||
rpush(...args: any[]): boolean;
|
||||
lpush(args: any[], callback?: any): boolean;
|
||||
lpush(...args: any[]): boolean;
|
||||
rpushx(args: any[], callback?: any): boolean;
|
||||
rpushx(...args: any[]): boolean;
|
||||
lpushx(args: any[], callback?: any): boolean;
|
||||
lpushx(...args: any[]): boolean;
|
||||
linsert(args: any[], callback?: any): boolean;
|
||||
linsert(...args: any[]): boolean;
|
||||
rpop(args: any[], callback?: any): boolean;
|
||||
rpop(...args: any[]): boolean;
|
||||
lpop(args: any[], callback?: any): boolean;
|
||||
lpop(...args: any[]): boolean;
|
||||
brpop(args: any[], callback?: any): boolean;
|
||||
brpop(...args: any[]): boolean;
|
||||
brpoplpush(args: any[], callback?: any): boolean;
|
||||
brpoplpush(...args: any[]): boolean;
|
||||
blpop(args: any[], callback?: any): boolean;
|
||||
blpop(...args: any[]): boolean;
|
||||
llen(args: any[], callback?: any): boolean;
|
||||
llen(...args: any[]): boolean;
|
||||
lindex(args: any[], callback?: any): boolean;
|
||||
lindex(...args: any[]): boolean;
|
||||
lset(args: any[], callback?: any): boolean;
|
||||
lset(...args: any[]): boolean;
|
||||
lrange(args: any[], callback?: any): boolean;
|
||||
lrange(...args: any[]): boolean;
|
||||
ltrim(args: any[], callback?: any): boolean;
|
||||
ltrim(...args: any[]): boolean;
|
||||
lrem(args: any[], callback?: any): boolean;
|
||||
lrem(...args: any[]): boolean;
|
||||
rpoplpush(args: any[], callback?: any): boolean;
|
||||
rpoplpush(...args: any[]): boolean;
|
||||
sadd(args: any[], callback?: any): boolean;
|
||||
sadd(...args: any[]): boolean;
|
||||
srem(args: any[], callback?: any): boolean;
|
||||
srem(...args: any[]): boolean;
|
||||
smove(args: any[], callback?: any): boolean;
|
||||
smove(...args: any[]): boolean;
|
||||
sismember(args: any[], callback?: any): boolean;
|
||||
sismember(...args: any[]): boolean;
|
||||
scard(args: any[], callback?: any): boolean;
|
||||
scard(...args: any[]): boolean;
|
||||
spop(args: any[], callback?: any): boolean;
|
||||
spop(...args: any[]): boolean;
|
||||
srandmember(args: any[], callback?: any): boolean;
|
||||
srandmember(...args: any[]): boolean;
|
||||
sinter(args: any[], callback?: any): boolean;
|
||||
sinter(...args: any[]): boolean;
|
||||
sinterstore(args: any[], callback?: any): boolean;
|
||||
sinterstore(...args: any[]): boolean;
|
||||
sunion(args: any[], callback?: any): boolean;
|
||||
sunion(...args: any[]): boolean;
|
||||
sunionstore(args: any[], callback?: any): boolean;
|
||||
sunionstore(...args: any[]): boolean;
|
||||
sdiff(args: any[], callback?: any): boolean;
|
||||
sdiff(...args: any[]): boolean;
|
||||
sdiffstore(args: any[], callback?: any): boolean;
|
||||
sdiffstore(...args: any[]): boolean;
|
||||
smembers(args: any[], callback?: any): boolean;
|
||||
smembers(...args: any[]): boolean;
|
||||
zadd(args: any[], callback?: any): boolean;
|
||||
zadd(...args: any[]): boolean;
|
||||
zincrby(args: any[], callback?: any): boolean;
|
||||
zincrby(...args: any[]): boolean;
|
||||
zrem(args: any[], callback?: any): boolean;
|
||||
zrem(...args: any[]): boolean;
|
||||
zremrangebyscore(args: any[], callback?: any): boolean;
|
||||
zremrangebyscore(...args: any[]): boolean;
|
||||
zremrangebyrank(args: any[], callback?: any): boolean;
|
||||
zremrangebyrank(...args: any[]): boolean;
|
||||
zunionstore(args: any[], callback?: any): boolean;
|
||||
zunionstore(...args: any[]): boolean;
|
||||
zinterstore(args: any[], callback?: any): boolean;
|
||||
zinterstore(...args: any[]): boolean;
|
||||
zrange(args: any[], callback?: any): boolean;
|
||||
zrange(...args: any[]): boolean;
|
||||
zrangebyscore(args: any[], callback?: any): boolean;
|
||||
zrangebyscore(...args: any[]): boolean;
|
||||
zrevrangebyscore(args: any[], callback?: any): boolean;
|
||||
zrevrangebyscore(...args: any[]): boolean;
|
||||
zcount(args: any[], callback?: any): boolean;
|
||||
zcount(...args: any[]): boolean;
|
||||
zrevrange(args: any[], callback?: any): boolean;
|
||||
zrevrange(...args: any[]): boolean;
|
||||
zcard(args: any[], callback?: any): boolean;
|
||||
zcard(...args: any[]): boolean;
|
||||
zscore(args: any[], callback?: any): boolean;
|
||||
zscore(...args: any[]): boolean;
|
||||
zrank(args: any[], callback?: any): boolean;
|
||||
zrank(...args: any[]): boolean;
|
||||
zrevrank(args: any[], callback?: any): boolean;
|
||||
zrevrank(...args: any[]): boolean;
|
||||
hset(args: any[], callback?: any): boolean;
|
||||
hset(...args: any[]): boolean;
|
||||
hsetnx(args: any[], callback?: any): boolean;
|
||||
hsetnx(...args: any[]): boolean;
|
||||
hget(args: any[], callback?: any): boolean;
|
||||
hget(...args: any[]): boolean;
|
||||
hmset(args: any[], callback?: any): boolean;
|
||||
hmset(key: string, hash: any, callback?: any): boolean;
|
||||
hmset(...args: any[]): boolean;
|
||||
hmget(args: any[], callback?: any): boolean;
|
||||
hmget(...args: any[]): boolean;
|
||||
hincrby(args: any[], callback?: any): boolean;
|
||||
hincrby(...args: any[]): boolean;
|
||||
hincrbyfloat(args: any[], callback?: any): boolean;
|
||||
hincrbyfloat(...args: any[]): boolean;
|
||||
hdel(args: any[], callback?: any): boolean;
|
||||
hdel(...args: any[]): boolean;
|
||||
hlen(args: any[], callback?: any): boolean;
|
||||
hlen(...args: any[]): boolean;
|
||||
hkeys(args: any[], callback?: any): boolean;
|
||||
hkeys(...args: any[]): boolean;
|
||||
hvals(args: any[], callback?: any): boolean;
|
||||
hvals(...args: any[]): boolean;
|
||||
hgetall(args: any[], callback?: any): boolean;
|
||||
hgetall(...args: any[]): boolean;
|
||||
hgetall(key: string, callback?: any): boolean;
|
||||
hexists(args: any[], callback?: any): boolean;
|
||||
hexists(...args: any[]): boolean;
|
||||
incrby(args: any[], callback?: any): boolean;
|
||||
incrby(...args: any[]): boolean;
|
||||
decrby(args: any[], callback?: any): boolean;
|
||||
decrby(...args: any[]): boolean;
|
||||
getset(args: any[], callback?: any): boolean;
|
||||
getset(...args: any[]): boolean;
|
||||
mset(args: any[], callback?: any): boolean;
|
||||
mset(...args: any[]): boolean;
|
||||
msetnx(args: any[], callback?: any): boolean;
|
||||
msetnx(...args: any[]): boolean;
|
||||
randomkey(args: any[], callback?: any): boolean;
|
||||
randomkey(...args: any[]): boolean;
|
||||
select(args: any[], callback?: any): void;
|
||||
select(...args: any[]): void;
|
||||
move(args: any[], callback?: any): boolean;
|
||||
move(...args: any[]): boolean;
|
||||
rename(args: any[], callback?: any): boolean;
|
||||
rename(...args: any[]): boolean;
|
||||
renamenx(args: any[], callback?: any): boolean;
|
||||
renamenx(...args: any[]): boolean;
|
||||
expire(args: any[], callback?: any): boolean;
|
||||
expire(...args: any[]): boolean;
|
||||
expireat(args: any[], callback?: any): boolean;
|
||||
expireat(...args: any[]): boolean;
|
||||
keys(args: any[], callback?: any): boolean;
|
||||
keys(...args: any[]): boolean;
|
||||
dbsize(args: any[], callback?: any): boolean;
|
||||
dbsize(...args: any[]): boolean;
|
||||
auth(args: any[], callback?: any): void;
|
||||
auth(...args: any[]): void;
|
||||
ping(args: any[], callback?: any): boolean;
|
||||
ping(...args: any[]): boolean;
|
||||
echo(args: any[], callback?: any): boolean;
|
||||
echo(...args: any[]): boolean;
|
||||
save(args: any[], callback?: any): boolean;
|
||||
save(...args: any[]): boolean;
|
||||
bgsave(args: any[], callback?: any): boolean;
|
||||
bgsave(...args: any[]): boolean;
|
||||
bgrewriteaof(args: any[], callback?: any): boolean;
|
||||
bgrewriteaof(...args: any[]): boolean;
|
||||
shutdown(args: any[], callback?: any): boolean;
|
||||
shutdown(...args: any[]): boolean;
|
||||
lastsave(args: any[], callback?: any): boolean;
|
||||
lastsave(...args: any[]): boolean;
|
||||
type(args: any[], callback?: any): boolean;
|
||||
type(...args: any[]): boolean;
|
||||
any(args: any[], callback?: any): any;
|
||||
any(...args: any[]): any;
|
||||
exec(args: any[], callback?: any): boolean;
|
||||
exec(...args: any[]): boolean;
|
||||
discard(args: any[], callback?: any): boolean;
|
||||
discard(...args: any[]): boolean;
|
||||
sync(args: any[], callback?: any): boolean;
|
||||
sync(...args: any[]): boolean;
|
||||
flushdb(args: any[], callback?: any): boolean;
|
||||
flushdb(...args: any[]): boolean;
|
||||
flushall(args: any[], callback?: any): boolean;
|
||||
flushall(...args: any[]): boolean;
|
||||
sort(args: any[], callback?: any): boolean;
|
||||
sort(...args: any[]): boolean;
|
||||
info(args: any[], callback?: any): boolean;
|
||||
info(...args: any[]): boolean;
|
||||
monitor(args: any[], callback?: any): boolean;
|
||||
monitor(...args: any[]): boolean;
|
||||
ttl(args: any[], callback?: any): boolean;
|
||||
ttl(...args: any[]): boolean;
|
||||
persist(args: any[], callback?: any): boolean;
|
||||
persist(...args: any[]): boolean;
|
||||
slaveof(args: any[], callback?: any): boolean;
|
||||
slaveof(...args: any[]): boolean;
|
||||
debug(args: any[], callback?: any): boolean;
|
||||
debug(...args: any[]): boolean;
|
||||
config(args: any[], callback?: any): boolean;
|
||||
config(...args: any[]): boolean;
|
||||
subscribe(args: any[], callback?: any): boolean;
|
||||
subscribe(...args: any[]): boolean;
|
||||
unsubscribe(args: any[], callback?: any): boolean;
|
||||
unsubscribe(...args: any[]): boolean;
|
||||
psubscribe(args: any[], callback?: any): boolean;
|
||||
psubscribe(...args: any[]): boolean;
|
||||
punsubscribe(args: any[], callback?: any): boolean;
|
||||
punsubscribe(...args: any[]): boolean;
|
||||
publish(args: any[], callback?: any): boolean;
|
||||
publish(...args: any[]): boolean;
|
||||
watch(args: any[], callback?: any): boolean;
|
||||
watch(...args: any[]): boolean;
|
||||
unwatch(args: any[], callback?: any): boolean;
|
||||
unwatch(...args: any[]): boolean;
|
||||
cluster(args: any[], callback?: any): boolean;
|
||||
cluster(...args: any[]): boolean;
|
||||
restore(args: any[], callback?: any): boolean;
|
||||
restore(...args: any[]): boolean;
|
||||
migrate(args: any[], callback?: any): boolean;
|
||||
migrate(...args: any[]): boolean;
|
||||
dump(args: any[], callback?: any): boolean;
|
||||
dump(...args: any[]): boolean;
|
||||
object(args: any[], callback?: any): boolean;
|
||||
object(...args: any[]): boolean;
|
||||
client(args: any[], callback?: any): boolean;
|
||||
client(...args: any[]): boolean;
|
||||
eval(args: any[], callback?: any): boolean;
|
||||
eval(...args: any[]): boolean;
|
||||
evalsha(args: any[], callback?: any): boolean;
|
||||
evalsha(...args: any[]): boolean;
|
||||
script(args: any[], callback?: any): boolean;
|
||||
script(...args: any[]): boolean;
|
||||
script(key: string, callback?: any): boolean;
|
||||
quit(args: any[], callback?: any): boolean;
|
||||
quit(...args: any[]): boolean;
|
||||
sscan(...args: any[]): boolean;
|
||||
sscan(args: any[], callback?: any): boolean;
|
||||
scan(...args: any[]): boolean;
|
||||
scan(args: any[], callback?: any): boolean;
|
||||
hscan(...args: any[]): boolean;
|
||||
hscan(args: any[], callback?: any): boolean;
|
||||
zscan(...args: any[]): boolean;
|
||||
zscan(args: any[], callback?: any): boolean;
|
||||
|
||||
// Extras
|
||||
duplicate(options?: any[], callback?: any): RedisClient;
|
||||
enableOfflineQueue?: boolean | undefined;
|
||||
/**
|
||||
* The milliseconds before a timeout occurs during the initial connection to the Redis server.
|
||||
* default: 10000.
|
||||
*/
|
||||
connectTimeout?: number | undefined;
|
||||
/**
|
||||
* The milliseconds before socket.destroy() is called after socket.end() if the connection remains half-open during disconnection.
|
||||
* default: 2000
|
||||
*/
|
||||
disconnectTimeout?: number | undefined;
|
||||
/**
|
||||
* After reconnected, if the previous connection was in the subscriber mode, client will auto re-subscribe these channels.
|
||||
* default: true.
|
||||
*/
|
||||
autoResubscribe?: boolean | undefined;
|
||||
/**
|
||||
* If true, client will resend unfulfilled commands(e.g. block commands) in the previous connection when reconnected.
|
||||
* default: true.
|
||||
*/
|
||||
autoResendUnfulfilledCommands?: boolean | undefined;
|
||||
lazyConnect?: boolean | undefined;
|
||||
tls?: any | undefined;
|
||||
/**
|
||||
* default: "master".
|
||||
*/
|
||||
role?: 'master' | 'slave' | undefined;
|
||||
/**
|
||||
* default: null.
|
||||
*/
|
||||
name?: string | undefined;
|
||||
sentinelUsername?: string | undefined;
|
||||
sentinelPassword?: string | undefined;
|
||||
sentinels?: Array<{ host: string; port: number }> | undefined;
|
||||
/**
|
||||
* If `sentinelRetryStrategy` returns a valid delay time, ioredis will try to reconnect from scratch.
|
||||
* default: function(times) { return Math.min(times * 10, 1000); }
|
||||
*/
|
||||
sentinelRetryStrategy?(times: number): number | void | null;
|
||||
/**
|
||||
* Can be used to prefer a particular slave or set of slaves based on priority.
|
||||
*/
|
||||
preferredSlaves?: any | undefined;
|
||||
/**
|
||||
* Whether to support the `tls` option when connecting to Redis via sentinel mode.
|
||||
* default: false.
|
||||
*/
|
||||
enableTLSForSentinelMode?: boolean | undefined;
|
||||
sentinelTLS?: any | undefined;
|
||||
/**
|
||||
* NAT map for sentinel connector.
|
||||
* default: null.
|
||||
*/
|
||||
natMap?: any | undefined;
|
||||
/**
|
||||
* Update the given `sentinels` list with new IP addresses when communicating with existing sentinels.
|
||||
* default: true.
|
||||
*/
|
||||
updateSentinels?: boolean | undefined;
|
||||
/**
|
||||
* Enable READONLY mode for the connection. Only available for cluster mode.
|
||||
* default: false.
|
||||
*/
|
||||
readOnly?: boolean | undefined;
|
||||
/**
|
||||
* If you are using the hiredis parser, it's highly recommended to enable this option.
|
||||
* Create another instance with dropBufferSupport disabled for other commands that you want to return binary instead of string
|
||||
*/
|
||||
dropBufferSupport?: boolean | undefined;
|
||||
/**
|
||||
* Whether to show a friendly error stack. Will decrease the performance significantly.
|
||||
*/
|
||||
showFriendlyErrorStack?: boolean | undefined;
|
||||
/**
|
||||
* When enabled, all commands issued during an event loop iteration are automatically wrapped in a
|
||||
* pipeline and sent to the server at the same time. This can improve performance by 30-50%.
|
||||
* default: false.
|
||||
*/
|
||||
enableAutoPipelining?: boolean | undefined;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
ProducerRecord,
|
||||
} from '../external/kafka.interface';
|
||||
import { MqttClientOptions, QoS } from '../external/mqtt-options.interface';
|
||||
import { ClientOpts } from '../external/redis.interface';
|
||||
import { IORedisOptions } from '../external/redis.interface';
|
||||
import { RmqUrl } from '../external/rmq-url.interface';
|
||||
import { TcpSocket } from '../helpers';
|
||||
import { CustomTransportStrategy } from './custom-transport-strategy.interface';
|
||||
@@ -91,7 +91,7 @@ export interface RedisOptions {
|
||||
retryDelay?: number;
|
||||
serializer?: Serializer;
|
||||
deserializer?: Deserializer;
|
||||
} & ClientOpts;
|
||||
} & IORedisOptions;
|
||||
}
|
||||
|
||||
export interface MqttOptions {
|
||||
|
||||
@@ -1,41 +1,37 @@
|
||||
import { isUndefined } from '@nestjs/common/utils/shared.utils';
|
||||
import { Observable } from 'rxjs';
|
||||
import {
|
||||
CONNECT_EVENT,
|
||||
ERROR_EVENT,
|
||||
MESSAGE_EVENT,
|
||||
NO_MESSAGE_HANDLER,
|
||||
REDIS_DEFAULT_URL,
|
||||
REDIS_DEFAULT_HOST,
|
||||
REDIS_DEFAULT_PORT,
|
||||
} from '../constants';
|
||||
import { RedisContext } from '../ctx-host';
|
||||
import { Transport } from '../enums';
|
||||
import {
|
||||
ClientOpts,
|
||||
RedisClient,
|
||||
RetryStrategyOptions,
|
||||
} from '../external/redis.interface';
|
||||
import { CustomTransportStrategy, IncomingRequest } from '../interfaces';
|
||||
import { RedisOptions } from '../interfaces/microservice-configuration.interface';
|
||||
CustomTransportStrategy,
|
||||
IncomingRequest,
|
||||
RedisOptions,
|
||||
} from '../interfaces';
|
||||
import { Server } from './server';
|
||||
|
||||
let redisPackage: any = {};
|
||||
type Redis = any;
|
||||
|
||||
let redisPackage = {} as any;
|
||||
|
||||
export class ServerRedis extends Server implements CustomTransportStrategy {
|
||||
public readonly transportId = Transport.REDIS;
|
||||
|
||||
private readonly url: string;
|
||||
private subClient: RedisClient;
|
||||
private pubClient: RedisClient;
|
||||
private subClient: Redis;
|
||||
private pubClient: Redis;
|
||||
private isExplicitlyTerminated = false;
|
||||
|
||||
constructor(private readonly options: RedisOptions['options']) {
|
||||
super();
|
||||
this.url =
|
||||
this.getOptionsProp(options, 'url') ||
|
||||
(!this.getOptionsProp(options, 'host') && REDIS_DEFAULT_URL);
|
||||
|
||||
redisPackage = this.loadPackage('redis', ServerRedis.name, () =>
|
||||
require('redis'),
|
||||
redisPackage = this.loadPackage('ioredis', ServerRedis.name, () =>
|
||||
require('ioredis'),
|
||||
);
|
||||
|
||||
this.initializeSerializer(options);
|
||||
@@ -51,6 +47,7 @@ export class ServerRedis extends Server implements CustomTransportStrategy {
|
||||
|
||||
this.handleError(this.pubClient);
|
||||
this.handleError(this.subClient);
|
||||
|
||||
this.start(callback);
|
||||
} catch (err) {
|
||||
callback(err);
|
||||
@@ -58,11 +55,15 @@ export class ServerRedis extends Server implements CustomTransportStrategy {
|
||||
}
|
||||
|
||||
public start(callback?: () => void) {
|
||||
this.bindEvents(this.subClient, this.pubClient);
|
||||
this.subClient.on(CONNECT_EVENT, callback);
|
||||
Promise.all([this.subClient.connect(), this.pubClient.connect()])
|
||||
.then(() => {
|
||||
this.bindEvents(this.subClient, this.pubClient);
|
||||
callback();
|
||||
})
|
||||
.catch(callback);
|
||||
}
|
||||
|
||||
public bindEvents(subClient: RedisClient, pubClient: RedisClient) {
|
||||
public bindEvents(subClient: Redis, pubClient: Redis) {
|
||||
subClient.on(MESSAGE_EVENT, this.getMessageHandler(pubClient).bind(this));
|
||||
const subscribePatterns = [...this.messageHandlers.keys()];
|
||||
subscribePatterns.forEach(pattern => {
|
||||
@@ -79,14 +80,16 @@ export class ServerRedis extends Server implements CustomTransportStrategy {
|
||||
this.subClient && this.subClient.quit();
|
||||
}
|
||||
|
||||
public createRedisClient(): RedisClient {
|
||||
return redisPackage.createClient({
|
||||
public createRedisClient(): Redis {
|
||||
return new redisPackage({
|
||||
port: REDIS_DEFAULT_PORT,
|
||||
host: REDIS_DEFAULT_HOST,
|
||||
...this.getClientOptions(),
|
||||
url: this.url,
|
||||
lazyConnect: true,
|
||||
});
|
||||
}
|
||||
|
||||
public getMessageHandler(pub: RedisClient) {
|
||||
public getMessageHandler(pub: Redis) {
|
||||
return async (channel: string, buffer: string | any) =>
|
||||
this.handleMessage(channel, buffer, pub);
|
||||
}
|
||||
@@ -94,7 +97,7 @@ export class ServerRedis extends Server implements CustomTransportStrategy {
|
||||
public async handleMessage(
|
||||
channel: string,
|
||||
buffer: string | any,
|
||||
pub: RedisClient,
|
||||
pub: Redis,
|
||||
) {
|
||||
const rawMessage = this.parseMessage(buffer);
|
||||
const packet = await this.deserializer.deserialize(rawMessage, { channel });
|
||||
@@ -125,7 +128,7 @@ export class ServerRedis extends Server implements CustomTransportStrategy {
|
||||
response$ && this.send(response$, publish);
|
||||
}
|
||||
|
||||
public getPublisher(pub: RedisClient, pattern: any, id: string) {
|
||||
public getPublisher(pub: Redis, pattern: any, id: string) {
|
||||
return (response: any) => {
|
||||
Object.assign(response, { id });
|
||||
const outgoingResponse = this.serializer.serialize(response);
|
||||
@@ -157,31 +160,25 @@ export class ServerRedis extends Server implements CustomTransportStrategy {
|
||||
stream.on(ERROR_EVENT, (err: any) => this.logger.error(err));
|
||||
}
|
||||
|
||||
public getClientOptions(): Partial<ClientOpts> {
|
||||
const retry_strategy = (options: RetryStrategyOptions) =>
|
||||
this.createRetryStrategy(options);
|
||||
public getClientOptions(): Partial<RedisOptions['options']> {
|
||||
const retryStrategy = (times: number) => this.createRetryStrategy(times);
|
||||
|
||||
return {
|
||||
...(this.options || {}),
|
||||
retry_strategy,
|
||||
retryStrategy,
|
||||
};
|
||||
}
|
||||
|
||||
public createRetryStrategy(
|
||||
options: RetryStrategyOptions,
|
||||
): undefined | number | void {
|
||||
if (options.error && (options.error as any).code === 'ECONNREFUSED') {
|
||||
this.logger.error(`Error ECONNREFUSED: ${this.url}`);
|
||||
}
|
||||
public createRetryStrategy(times: number): undefined | number | void {
|
||||
if (this.isExplicitlyTerminated) {
|
||||
return undefined;
|
||||
}
|
||||
if (
|
||||
!this.getOptionsProp(this.options, 'retryAttempts') ||
|
||||
options.attempt > this.getOptionsProp(this.options, 'retryAttempts')
|
||||
times > this.getOptionsProp(this.options, 'retryAttempts')
|
||||
) {
|
||||
this.logger.error(`Retry time exhausted: ${this.url}`);
|
||||
throw new Error('Retry time exhausted');
|
||||
this.logger.error(`Retry time exhausted`);
|
||||
return;
|
||||
}
|
||||
return this.getOptionsProp(this.options, 'retryDelay') || 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user