@midwayjs/redis 3.20.4 → 4.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -34,7 +34,8 @@ let RedisConfiguration = class RedisConfiguration {
34
34
  };
35
35
  }
36
36
  };
37
- RedisConfiguration = __decorate([
37
+ exports.RedisConfiguration = RedisConfiguration;
38
+ exports.RedisConfiguration = RedisConfiguration = __decorate([
38
39
  (0, core_1.Configuration)({
39
40
  namespace: 'redis',
40
41
  importConfigs: [
@@ -46,5 +47,4 @@ RedisConfiguration = __decorate([
46
47
  ],
47
48
  })
48
49
  ], RedisConfiguration);
49
- exports.RedisConfiguration = RedisConfiguration;
50
50
  //# sourceMappingURL=configuration.js.map
@@ -0,0 +1,68 @@
1
+ import { ServiceDiscovery, ServiceDiscoveryClient, DataListener, ILogger } from '@midwayjs/core';
2
+ import { RedisServiceDiscoveryOptions, RedisInstanceMetadata } from '../interface';
3
+ import Redis from 'ioredis';
4
+ declare class RedisDataListener extends DataListener<RedisInstanceMetadata[]> {
5
+ protected readonly client: Redis;
6
+ protected readonly pubsub: Redis;
7
+ protected readonly options: RedisServiceDiscoveryOptions;
8
+ protected readonly logger: ILogger;
9
+ private unsubscribe;
10
+ private ttlTimeout;
11
+ private instance;
12
+ private instanceKey;
13
+ private serviceName;
14
+ constructor(serviceName: string, client: Redis, pubsub: Redis, options: RedisServiceDiscoveryOptions, logger: ILogger);
15
+ init(): Promise<void>;
16
+ initData(): Promise<RedisInstanceMetadata[]>;
17
+ onData(setData: any): void;
18
+ destroyListener(): Promise<void>;
19
+ onlineInstance(instance?: RedisInstanceMetadata): Promise<void>;
20
+ offlineInstance(instance?: RedisInstanceMetadata): Promise<void>;
21
+ /**
22
+ * 生成实例唯一 key
23
+ * 格式: <prefix><serviceName>:instance:<instanceId>
24
+ * 例: services:order:instance:abc123
25
+ */
26
+ private getInstanceKey;
27
+ private startTTLRefresh;
28
+ private clearTTLRefresh;
29
+ /**
30
+ * 使用 SCAN 替代 KEYS,游标式遍历所有匹配的 key
31
+ */
32
+ private scanKeys;
33
+ /**
34
+ * 批量获取实例 key 并反序列化为对象数组
35
+ */
36
+ private fetchInstancesByKeys;
37
+ }
38
+ export declare class RedisServiceDiscoverClient extends ServiceDiscoveryClient<Redis, RedisServiceDiscoveryOptions, RedisInstanceMetadata> {
39
+ protected redis: Redis;
40
+ protected serviceDiscoveryOptions: RedisServiceDiscoveryOptions;
41
+ protected logger: ILogger;
42
+ protected getListener: (serviceName: string) => Promise<RedisDataListener>;
43
+ private registeredInstance;
44
+ private onlineInstanceData;
45
+ constructor(redis: Redis, serviceDiscoveryOptions: RedisServiceDiscoveryOptions, logger: ILogger, getListener: (serviceName: string) => Promise<RedisDataListener>);
46
+ register(instance: RedisInstanceMetadata): Promise<void>;
47
+ deregister(): Promise<void>;
48
+ online(): Promise<void>;
49
+ offline(): Promise<void>;
50
+ beforeStop(): Promise<void>;
51
+ }
52
+ export declare class RedisServiceDiscovery extends ServiceDiscovery<Redis, RedisServiceDiscoveryOptions, RedisInstanceMetadata, RedisInstanceMetadata, string> {
53
+ private redisServiceFactory;
54
+ private configService;
55
+ private coreLogger;
56
+ private redisServiceDiscoveryOptions;
57
+ private listenerStore;
58
+ private pubsub;
59
+ init(): Promise<void>;
60
+ getServiceClient(): Redis;
61
+ protected createServiceDiscoverClientImpl(options: RedisServiceDiscoveryOptions): RedisServiceDiscoverClient;
62
+ protected getDefaultServiceDiscoveryOptions(): RedisServiceDiscoveryOptions;
63
+ private getListener;
64
+ getInstances(serviceName: string): Promise<RedisInstanceMetadata[]>;
65
+ beforeStop(): Promise<void>;
66
+ }
67
+ export {};
68
+ //# sourceMappingURL=serviceDiscovery.d.ts.map
@@ -0,0 +1,312 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.RedisServiceDiscovery = exports.RedisServiceDiscoverClient = void 0;
13
+ const core_1 = require("@midwayjs/core");
14
+ const manager_1 = require("../manager");
15
+ class RedisDataListener extends core_1.DataListener {
16
+ constructor(serviceName, client, pubsub, options, logger) {
17
+ super();
18
+ this.client = client;
19
+ this.pubsub = pubsub;
20
+ this.options = options;
21
+ this.logger = logger;
22
+ this.unsubscribe = null;
23
+ // 新增:定时刷新 TTL
24
+ this.ttlTimeout = null;
25
+ this.instance = null;
26
+ this.instanceKey = null;
27
+ this.serviceName = serviceName;
28
+ }
29
+ async init() {
30
+ await super.init();
31
+ }
32
+ async initData() {
33
+ // 1. 用 SCAN 替代 KEYS 获取所有实例 key
34
+ const keys = await this.scanKeys(`${this.options.prefix}${this.serviceName}:instance:*`);
35
+ return this.fetchInstancesByKeys(keys);
36
+ }
37
+ onData(setData) {
38
+ // 订阅当前 serviceName 的变更消息
39
+ const channel = `service:change:${this.serviceName}`;
40
+ const handler = async (channelName, message) => {
41
+ this.logger.debug(`[midway:redis] pubsub event received: channel=${channelName}, message=${message}`);
42
+ if (channelName !== channel)
43
+ return;
44
+ try {
45
+ // 变更时重新拉取全量数据
46
+ const keys = await this.scanKeys(`${this.options.prefix}${this.serviceName}:instance:*`);
47
+ setData(await this.fetchInstancesByKeys(keys));
48
+ }
49
+ catch (err) {
50
+ this.logger.error('[midway:redis] Error on service change:', err);
51
+ }
52
+ };
53
+ this.pubsub.subscribe(channel);
54
+ this.pubsub.on('message', handler);
55
+ // 提供取消订阅方法
56
+ this.unsubscribe = () => {
57
+ this.pubsub.off('message', handler);
58
+ this.pubsub.unsubscribe(channel);
59
+ };
60
+ }
61
+ async destroyListener() {
62
+ this.clearTTLRefresh();
63
+ if (this.unsubscribe) {
64
+ this.unsubscribe();
65
+ this.unsubscribe = null;
66
+ }
67
+ }
68
+ // 新增:上线时启动 TTL 刷新
69
+ async onlineInstance(instance) {
70
+ instance = this.instance = instance || this.instance;
71
+ this.instanceKey = this.getInstanceKey(instance.serviceName, instance.id);
72
+ const data = { ...instance, status: 'UP' };
73
+ const ttl = instance.ttl || this.options.ttl || 30;
74
+ this.logger.debug(`[midway:redis] set key: ${this.instanceKey}, value: ${JSON.stringify(data)}, ttl: ${ttl}`);
75
+ await this.client.set(this.instanceKey, JSON.stringify(data), 'EX', ttl);
76
+ this.startTTLRefresh();
77
+ const testKeys = await this.client.scan('0', 'MATCH', `${this.options.prefix}${instance.serviceName}:instance:*`, 'COUNT', 100);
78
+ this.logger.debug(`[midway:redis] after set, scan test: ${JSON.stringify(testKeys)}`);
79
+ }
80
+ // 新增:下线时清理 TTL 刷新
81
+ async offlineInstance(instance) {
82
+ instance = instance || this.instance;
83
+ this.clearTTLRefresh();
84
+ const instanceKey = this.getInstanceKey(instance.serviceName, instance.id);
85
+ await this.client.del(instanceKey);
86
+ }
87
+ /**
88
+ * 生成实例唯一 key
89
+ * 格式: <prefix><serviceName>:instance:<instanceId>
90
+ * 例: services:order:instance:abc123
91
+ */
92
+ getInstanceKey(serviceName, instanceId) {
93
+ return `${this.options.prefix}${serviceName}:instance:${instanceId}`;
94
+ }
95
+ startTTLRefresh() {
96
+ this.clearTTLRefresh();
97
+ if (!this.instance)
98
+ return;
99
+ const ttl = this.instance.ttl || this.options.ttl || 30;
100
+ const interval = Math.max(ttl * 500, 1000);
101
+ const refresh = async () => {
102
+ try {
103
+ if (this.instanceKey && this.instance) {
104
+ const data = { ...this.instance, status: 'UP' };
105
+ await this.client.set(this.instanceKey, JSON.stringify(data), 'EX', ttl);
106
+ }
107
+ }
108
+ catch (err) {
109
+ this.logger.error('[midway:redis] TTL refresh failed:', err);
110
+ }
111
+ this.ttlTimeout = setTimeout(refresh, interval);
112
+ };
113
+ refresh();
114
+ }
115
+ clearTTLRefresh() {
116
+ if (this.ttlTimeout) {
117
+ clearTimeout(this.ttlTimeout);
118
+ this.ttlTimeout = null;
119
+ }
120
+ }
121
+ /**
122
+ * 使用 SCAN 替代 KEYS,游标式遍历所有匹配的 key
123
+ */
124
+ async scanKeys(pattern, count) {
125
+ let cursor = '0';
126
+ let keys = [];
127
+ const scanCount = count || this.options.scanCount || 100;
128
+ do {
129
+ const [nextCursor, foundKeys] = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', scanCount);
130
+ cursor = nextCursor;
131
+ keys = keys.concat(foundKeys);
132
+ } while (cursor !== '0');
133
+ this.logger.debug(`[midway:redis] scanKeys pattern=${pattern}, found keys=${JSON.stringify(keys)}`);
134
+ return keys;
135
+ }
136
+ /**
137
+ * 批量获取实例 key 并反序列化为对象数组
138
+ */
139
+ async fetchInstancesByKeys(keys) {
140
+ if (keys.length === 0)
141
+ return [];
142
+ const values = await this.client.mget(keys);
143
+ return values
144
+ .map(value => {
145
+ try {
146
+ return JSON.parse(value);
147
+ }
148
+ catch {
149
+ return null;
150
+ }
151
+ })
152
+ .filter(Boolean);
153
+ }
154
+ }
155
+ class RedisServiceDiscoverClient extends core_1.ServiceDiscoveryClient {
156
+ constructor(redis, serviceDiscoveryOptions, logger, getListener) {
157
+ super(redis, serviceDiscoveryOptions);
158
+ this.redis = redis;
159
+ this.serviceDiscoveryOptions = serviceDiscoveryOptions;
160
+ this.logger = logger;
161
+ this.getListener = getListener;
162
+ this.registeredInstance = null;
163
+ this.onlineInstanceData = null;
164
+ }
165
+ async register(instance) {
166
+ this.registeredInstance = instance;
167
+ if (!instance.serviceName) {
168
+ throw new core_1.MidwayConfigMissingError('instance.serviceName is required when register service in redis');
169
+ }
170
+ // 注册时默认上线
171
+ await this.online();
172
+ this.logger.info(`[midway:redis] register instance: ${instance.id} for service: ${instance.serviceName}`);
173
+ }
174
+ async deregister() {
175
+ if (this.onlineInstanceData) {
176
+ await this.offline();
177
+ }
178
+ if (this.registeredInstance) {
179
+ // 发布服务变更消息
180
+ await this.client.publish(`service:change:${this.registeredInstance.serviceName}`, JSON.stringify({
181
+ type: 'deregister',
182
+ service: this.registeredInstance.serviceName,
183
+ instance: this.registeredInstance,
184
+ }));
185
+ this.logger.info(`[midway:redis] deregister instance: ${this.registeredInstance.id} for service: ${this.registeredInstance.serviceName}`);
186
+ this.registeredInstance = null;
187
+ }
188
+ }
189
+ async online() {
190
+ this.logger.debug('[midway:redis] online() called');
191
+ this.logger.debug(`[midway:redis] registeredInstance: ${JSON.stringify(this.registeredInstance)}`);
192
+ if (!this.registeredInstance) {
193
+ this.logger.error('[midway:redis] online() failed: No instance registered.');
194
+ throw new Error('No instance registered, cannot online.');
195
+ }
196
+ // 已经上线则忽略
197
+ if (this.onlineInstanceData) {
198
+ this.logger.debug('[midway:redis] online() ignored: already online.');
199
+ return;
200
+ }
201
+ const listener = await this.getListener(this.registeredInstance.serviceName);
202
+ await listener.onlineInstance(this.registeredInstance);
203
+ this.onlineInstanceData = this.registeredInstance;
204
+ this.logger.info(`[midway:redis] online() success: instance ${this.registeredInstance.id} for service ${this.registeredInstance.serviceName}`);
205
+ // 发布上线消息
206
+ await this.client.publish(`service:change:${this.registeredInstance.serviceName}`, JSON.stringify({
207
+ type: 'online',
208
+ service: this.registeredInstance.serviceName,
209
+ instance: this.registeredInstance,
210
+ }));
211
+ }
212
+ async offline() {
213
+ this.logger.debug('[midway:redis] offline() called');
214
+ this.logger.debug(`[midway:redis] onlineInstanceData: ${JSON.stringify(this.onlineInstanceData)}`);
215
+ // 已经下线则忽略
216
+ if (!this.onlineInstanceData) {
217
+ this.logger.info('[midway:redis] offline() ignored: already offline.');
218
+ return;
219
+ }
220
+ const listener = await this.getListener(this.onlineInstanceData.serviceName);
221
+ await listener.offlineInstance(this.onlineInstanceData);
222
+ this.logger.info(`[midway:redis] offline() success: instance ${this.onlineInstanceData.id} for service ${this.onlineInstanceData.serviceName}`);
223
+ // 发布下线消息
224
+ await this.client.publish(`service:change:${this.onlineInstanceData.serviceName}`, JSON.stringify({
225
+ type: 'offline',
226
+ service: this.onlineInstanceData.serviceName,
227
+ instance: this.onlineInstanceData,
228
+ }));
229
+ this.onlineInstanceData = null;
230
+ }
231
+ async beforeStop() { }
232
+ }
233
+ exports.RedisServiceDiscoverClient = RedisServiceDiscoverClient;
234
+ let RedisServiceDiscovery = class RedisServiceDiscovery extends core_1.ServiceDiscovery {
235
+ constructor() {
236
+ super(...arguments);
237
+ this.listenerStore = new Map();
238
+ }
239
+ async init() {
240
+ this.redisServiceDiscoveryOptions = this.configService.getConfiguration('redis.serviceDiscovery', {});
241
+ this.redisServiceDiscoveryOptions.prefix =
242
+ this.redisServiceDiscoveryOptions.prefix || 'services:';
243
+ }
244
+ getServiceClient() {
245
+ return this.redisServiceFactory.get(this.redisServiceDiscoveryOptions.serviceDiscoveryClient ||
246
+ this.redisServiceFactory.getDefaultClientName() ||
247
+ 'default');
248
+ }
249
+ createServiceDiscoverClientImpl(options) {
250
+ return new RedisServiceDiscoverClient(this.getServiceClient(), options, this.coreLogger, serviceName => this.getListener(serviceName));
251
+ }
252
+ getDefaultServiceDiscoveryOptions() {
253
+ return this.redisServiceDiscoveryOptions;
254
+ }
255
+ async getListener(serviceName) {
256
+ if (!this.pubsub) {
257
+ this.pubsub = this.getServiceClient().duplicate();
258
+ }
259
+ // 日志:打印当前请求的 serviceName
260
+ this.coreLogger.debug(`[midway:redis] getListener called for serviceName: ${serviceName}`);
261
+ // 日志:打印当前 listenerStore keys
262
+ this.coreLogger.debug(`[midway:redis] listenerStore keys: ${Array.from(this.listenerStore.keys()).join(',')}`);
263
+ if (!this.listenerStore.has(serviceName)) {
264
+ this.coreLogger.debug(`[midway:redis] listener for ${serviceName} not found, creating new listener.`);
265
+ const listener = new RedisDataListener(serviceName, this.getServiceClient(), this.pubsub, this.redisServiceDiscoveryOptions, this.coreLogger);
266
+ this.listenerStore.set(serviceName, listener);
267
+ await listener.init();
268
+ this.coreLogger.debug(`[midway:redis] listener for ${serviceName} initialized.`);
269
+ }
270
+ else {
271
+ this.coreLogger.debug(`[midway:redis] listener for ${serviceName} found in cache.`);
272
+ }
273
+ return this.listenerStore.get(serviceName);
274
+ }
275
+ async getInstances(serviceName) {
276
+ // 优先从 listener 的缓存获取数据
277
+ const listener = await this.getListener(serviceName);
278
+ return listener.getData();
279
+ }
280
+ async beforeStop() {
281
+ await Promise.all(Array.from(this.listenerStore.values()).map(listener => listener.destroyListener()));
282
+ this.listenerStore.clear();
283
+ if (this.pubsub) {
284
+ await this.pubsub.unsubscribe();
285
+ await this.pubsub.quit();
286
+ this.pubsub = null;
287
+ }
288
+ }
289
+ };
290
+ exports.RedisServiceDiscovery = RedisServiceDiscovery;
291
+ __decorate([
292
+ (0, core_1.Inject)(),
293
+ __metadata("design:type", manager_1.RedisServiceFactory)
294
+ ], RedisServiceDiscovery.prototype, "redisServiceFactory", void 0);
295
+ __decorate([
296
+ (0, core_1.Inject)(),
297
+ __metadata("design:type", core_1.MidwayConfigService)
298
+ ], RedisServiceDiscovery.prototype, "configService", void 0);
299
+ __decorate([
300
+ (0, core_1.Logger)(),
301
+ __metadata("design:type", Object)
302
+ ], RedisServiceDiscovery.prototype, "coreLogger", void 0);
303
+ __decorate([
304
+ (0, core_1.Init)(),
305
+ __metadata("design:type", Function),
306
+ __metadata("design:paramtypes", []),
307
+ __metadata("design:returntype", Promise)
308
+ ], RedisServiceDiscovery.prototype, "init", null);
309
+ exports.RedisServiceDiscovery = RedisServiceDiscovery = __decorate([
310
+ (0, core_1.Singleton)()
311
+ ], RedisServiceDiscovery);
312
+ //# sourceMappingURL=serviceDiscovery.js.map
package/dist/index.d.ts CHANGED
@@ -2,5 +2,6 @@ import Redis from 'ioredis';
2
2
  export { RedisConfiguration as Configuration } from './configuration';
3
3
  export * from './manager';
4
4
  export * from './interface';
5
+ export * from './extension/serviceDiscovery';
5
6
  export { Redis };
6
7
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -21,4 +21,5 @@ var configuration_1 = require("./configuration");
21
21
  Object.defineProperty(exports, "Configuration", { enumerable: true, get: function () { return configuration_1.RedisConfiguration; } });
22
22
  __exportStar(require("./manager"), exports);
23
23
  __exportStar(require("./interface"), exports);
24
+ __exportStar(require("./extension/serviceDiscovery"), exports);
24
25
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,69 @@
1
1
  import * as Redis from 'ioredis';
2
2
  import { ClusterNode, ClusterOptions } from 'ioredis';
3
+ import { DefaultInstanceMetadata, ServiceDiscoveryBaseInstance, ServiceDiscoveryOptions, ServiceFactoryConfigOption } from '@midwayjs/core';
3
4
  export type RedisConfigOptions = Redis.RedisOptions | ({
4
- cluster?: boolean;
5
5
  nodes?: ClusterNode[];
6
6
  } & ClusterOptions);
7
+ export interface RedisInstanceMetadata extends ServiceDiscoveryBaseInstance {
8
+ /**
9
+ * 服务名称
10
+ */
11
+ serviceName: string;
12
+ /**
13
+ * 服务实例 ID
14
+ */
15
+ id: string;
16
+ /**
17
+ * 服务实例的地址
18
+ */
19
+ host: string;
20
+ /**
21
+ * 服务实例的端口
22
+ */
23
+ port: number;
24
+ /**
25
+ * 服务实例的过期时间(秒)
26
+ */
27
+ ttl?: number;
28
+ /**
29
+ * 服务实例的标签
30
+ */
31
+ tags?: string[];
32
+ /**
33
+ * 服务实例的元数据
34
+ */
35
+ meta?: Record<string, string>;
36
+ /**
37
+ * 服务实例的状态
38
+ */
39
+ status?: 'UP' | 'DOWN';
40
+ }
41
+ export interface RedisServiceDiscoveryOptions extends ServiceDiscoveryOptions<RedisInstanceMetadata> {
42
+ /**
43
+ * 服务信息的过期时间(秒)
44
+ */
45
+ ttl?: number;
46
+ /**
47
+ * 服务信息的 key 前缀
48
+ */
49
+ prefix?: string;
50
+ /**
51
+ * 服务实例配置
52
+ */
53
+ serviceOptions?: RedisInstanceMetadata | ((meta: DefaultInstanceMetadata) => RedisInstanceMetadata);
54
+ /**
55
+ * 下线状态的 TTL(秒)
56
+ */
57
+ downTTL?: number;
58
+ /**
59
+ * SCAN 命令每次遍历的数量,默认 100
60
+ */
61
+ scanCount?: number;
62
+ }
63
+ export type MidwayRedisConfigOptions = ServiceFactoryConfigOption<RedisConfigOptions> & {
64
+ /**
65
+ * Redis 服务发现配置
66
+ */
67
+ serviceDiscovery?: RedisServiceDiscoveryOptions;
68
+ };
7
69
  //# sourceMappingURL=interface.d.ts.map
package/dist/manager.d.ts CHANGED
@@ -5,9 +5,9 @@ export declare class RedisServiceFactory extends ServiceFactory<Redis> {
5
5
  protected redisConfig: ServiceFactoryConfigOption<RedisConfigOptions>;
6
6
  protected init(): Promise<void>;
7
7
  protected logger: ILogger;
8
- protected createClient(config: any): Promise<Redis>;
8
+ protected createClient(config: any, name: string): Promise<Redis>;
9
9
  getName(): string;
10
- protected destroyClient(redisInstance: any): Promise<void>;
10
+ protected destroyClient(redisInstance: Redis, name: string): Promise<void>;
11
11
  }
12
12
  export declare class RedisService implements Redis {
13
13
  private serviceFactory;
package/dist/manager.js CHANGED
@@ -15,38 +15,40 @@ const ioredis_1 = require("ioredis");
15
15
  const assert = require("assert");
16
16
  let RedisServiceFactory = class RedisServiceFactory extends core_1.ServiceFactory {
17
17
  async init() {
18
- await this.initClients(this.redisConfig);
18
+ await this.initClients(this.redisConfig, {
19
+ concurrent: true,
20
+ });
19
21
  }
20
- async createClient(config) {
22
+ async createClient(config, name) {
21
23
  let client;
22
24
  if (config.cluster === true) {
23
- assert(config.nodes && config.nodes.length !== 0, '[midway:redis] cluster nodes configuration is required when use cluster redis');
25
+ assert.ok(config.nodes && config.nodes.length !== 0, `[midway:redis] client(${name}) cluster nodes configuration is required when use cluster redis`);
24
26
  config.nodes.forEach(client => {
25
- assert(client.host && client.port, `[midway:redis] 'host: ${client.host}', 'port: ${client.port}' are required on config`);
27
+ assert.ok(client.host && client.port, `[midway:redis] client(${name}) 'host: ${client.host}', 'port: ${client.port}' are required on config`);
26
28
  });
27
- this.logger.info('[midway:redis] cluster connecting');
28
29
  client = new ioredis_1.default.Cluster(config.nodes, config);
30
+ this.logger.info('[midway:redis] cluster is connecting');
29
31
  }
30
32
  else if (config.sentinels) {
31
- assert(config.sentinels && config.sentinels.length !== 0, '[midway:redis] sentinels configuration is required when use redis sentinel');
33
+ assert.ok(config.sentinels && config.sentinels.length !== 0, `[midway:redis] client(${name}) sentinels configuration is required when use redis sentinel`);
32
34
  config.sentinels.forEach(sentinel => {
33
- assert(sentinel.host && sentinel.port, `[midway:redis] 'host: ${sentinel.host}', 'port: ${sentinel.port}' are required on config`);
35
+ assert.ok(sentinel.host && sentinel.port, `[midway:redis] client(${name}) 'host: ${sentinel.host}', 'port: ${sentinel.port}' are required on config`);
34
36
  });
35
- this.logger.info('[midway:redis] sentinel connecting start');
36
37
  client = new ioredis_1.default(config);
38
+ this.logger.info(`[midway:redis] client(${name}) sentinel is connecting`);
37
39
  }
38
40
  else {
39
- assert(config.host && config.port, `[midway:redis] 'host: ${config.host}', 'port: ${config.port}' are required on config`);
40
- this.logger.info('[midway:redis] server connecting redis://:***@%s:%s', config.host, config.port);
41
+ assert.ok(config.host && config.port, `[midway:redis] client(${name}) 'host: ${config.host}', 'port: ${config.port}' are required on config`);
41
42
  client = new ioredis_1.default(config);
43
+ this.logger.info(`[midway:redis] client(${name}) server is connecting redis://:***@${config.host}:${config.port}`);
42
44
  }
43
45
  await new Promise((resolve, reject) => {
44
- client.on('connect', () => {
45
- this.logger.info('[midway:redis] client connect success');
46
+ client.on('ready', () => {
47
+ this.logger.info(`[midway:redis] client(${name}) connect success`);
46
48
  resolve();
47
49
  });
48
50
  client.on('error', err => {
49
- this.logger.error('[midway:redis] client error: %s', err);
51
+ this.logger.error(`[midway:redis] client(${name}) error: ${err}`);
50
52
  reject(err);
51
53
  });
52
54
  });
@@ -55,20 +57,22 @@ let RedisServiceFactory = class RedisServiceFactory extends core_1.ServiceFactor
55
57
  getName() {
56
58
  return 'redis';
57
59
  }
58
- async destroyClient(redisInstance) {
60
+ async destroyClient(redisInstance, name) {
59
61
  try {
60
62
  if (redisInstance) {
61
63
  const canQuit = !['end', 'close'].includes(redisInstance.status);
62
64
  if (canQuit) {
63
65
  await redisInstance.quit();
66
+ this.logger.info(`[midway:redis] client(${name}) quit success`);
64
67
  }
65
68
  }
66
69
  }
67
70
  catch (error) {
68
- this.logger.error('[midway:redis] Redis quit failed.', error);
71
+ this.logger.error(`[midway:redis] client(${name}) Redis quit failed.`, error);
69
72
  }
70
73
  }
71
74
  };
75
+ exports.RedisServiceFactory = RedisServiceFactory;
72
76
  __decorate([
73
77
  (0, core_1.Config)('redis'),
74
78
  __metadata("design:type", Object)
@@ -83,20 +87,19 @@ __decorate([
83
87
  (0, core_1.Logger)('coreLogger'),
84
88
  __metadata("design:type", Object)
85
89
  ], RedisServiceFactory.prototype, "logger", void 0);
86
- RedisServiceFactory = __decorate([
90
+ exports.RedisServiceFactory = RedisServiceFactory = __decorate([
87
91
  (0, core_1.Provide)(),
88
92
  (0, core_1.Scope)(core_1.ScopeEnum.Singleton)
89
93
  ], RedisServiceFactory);
90
- exports.RedisServiceFactory = RedisServiceFactory;
91
94
  let RedisService = class RedisService {
92
95
  async init() {
93
- var _a, _b;
94
- this.instance = this.serviceFactory.get(((_b = (_a = this.serviceFactory).getDefaultClientName) === null || _b === void 0 ? void 0 : _b.call(_a)) || 'default');
96
+ this.instance = this.serviceFactory.get(this.serviceFactory.getDefaultClientName?.() || 'default');
95
97
  if (!this.instance) {
96
98
  throw new core_1.MidwayCommonError('redis default instance not found.');
97
99
  }
98
100
  }
99
101
  };
102
+ exports.RedisService = RedisService;
100
103
  __decorate([
101
104
  (0, core_1.Inject)(),
102
105
  __metadata("design:type", RedisServiceFactory)
@@ -107,11 +110,10 @@ __decorate([
107
110
  __metadata("design:paramtypes", []),
108
111
  __metadata("design:returntype", Promise)
109
112
  ], RedisService.prototype, "init", null);
110
- RedisService = __decorate([
113
+ exports.RedisService = RedisService = __decorate([
111
114
  (0, core_1.Provide)(),
112
115
  (0, core_1.Scope)(core_1.ScopeEnum.Singleton)
113
116
  ], RedisService);
114
- exports.RedisService = RedisService;
115
117
  (0, core_1.delegateTargetAllPrototypeMethod)(RedisService, ioredis_1.default);
116
118
  RedisService.prototype.defineCommand = function (name, definition) {
117
119
  this.instance.defineCommand(name, definition);
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { RedisConfigOptions } from './dist';
1
+ import { MidwayRedisConfigOptions } from './dist';
2
2
  export * from './dist/index';
3
3
 
4
4
  // Single Redis
@@ -48,6 +48,6 @@ export * from './dist/index';
48
48
 
49
49
  declare module '@midwayjs/core/dist/interface' {
50
50
  interface MidwayConfig {
51
- redis?: ServiceFactoryConfigOption<RedisConfigOptions>;
51
+ redis?: MidwayRedisConfigOptions;
52
52
  }
53
53
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@midwayjs/redis",
3
3
  "description": "midway redis component",
4
- "version": "3.20.4",
4
+ "version": "4.0.0-beta.1",
5
5
  "main": "dist/index.js",
6
6
  "typings": "index.d.ts",
7
7
  "files": [
@@ -10,8 +10,8 @@
10
10
  "index.d.ts"
11
11
  ],
12
12
  "devDependencies": {
13
- "@midwayjs/core": "^3.20.4",
14
- "@midwayjs/mock": "^3.20.4"
13
+ "@midwayjs/core": "^4.0.0-beta.1",
14
+ "@midwayjs/mock": "^4.0.0-beta.1"
15
15
  },
16
16
  "dependencies": {
17
17
  "ioredis": "5.4.2"
@@ -23,8 +23,8 @@
23
23
  "license": "MIT",
24
24
  "scripts": {
25
25
  "build": "tsc",
26
- "test": "node --require=ts-node/register ../../node_modules/.bin/jest --runInBand",
27
- "cov": "node --require=ts-node/register ../../node_modules/.bin/jest --runInBand --coverage --forceExit",
26
+ "test": "node -r ts-node/register ../../node_modules/jest/bin/jest.js --runInBand",
27
+ "cov": "node -r ts-node/register ../../node_modules/jest/bin/jest.js --runInBand --coverage --forceExit",
28
28
  "ci": "npm run test",
29
29
  "lint": "mwts check"
30
30
  },
@@ -35,5 +35,5 @@
35
35
  "type": "git",
36
36
  "url": "https://github.com/midwayjs/midway.git"
37
37
  },
38
- "gitHead": "c3fb65a7ada8829635f3c6af5ef83c65c3a43d79"
38
+ "gitHead": "832961ec3aff123c033197d8c00cb2bc9bad7ff8"
39
39
  }