@midwayjs/redis 4.0.0-alpha.1 → 4.0.0-beta.10

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.
package/README.md CHANGED
@@ -9,4 +9,4 @@ Document: [https://midwayjs.org](https://midwayjs.org)
9
9
 
10
10
  ## License
11
11
 
12
- [MIT]((http://github.com/midwayjs/midway/blob/master/LICENSE))
12
+ [MIT](https://github.com/midwayjs/midway/blob/master/LICENSE)
@@ -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,323 @@
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
+ client;
17
+ pubsub;
18
+ options;
19
+ logger;
20
+ unsubscribe = null;
21
+ // 新增:定时刷新 TTL
22
+ ttlTimeout = null;
23
+ instance = null;
24
+ instanceKey = null;
25
+ serviceName;
26
+ constructor(serviceName, client, pubsub, options, logger) {
27
+ super();
28
+ this.client = client;
29
+ this.pubsub = pubsub;
30
+ this.options = options;
31
+ this.logger = logger;
32
+ this.serviceName = serviceName;
33
+ }
34
+ async init() {
35
+ await super.init();
36
+ }
37
+ async initData() {
38
+ // 1. 用 SCAN 替代 KEYS 获取所有实例 key
39
+ const keys = await this.scanKeys(`${this.options.prefix}${this.serviceName}:instance:*`);
40
+ return this.fetchInstancesByKeys(keys);
41
+ }
42
+ onData(setData) {
43
+ // 订阅当前 serviceName 的变更消息
44
+ const channel = `service:change:${this.serviceName}`;
45
+ const handler = async (channelName, message) => {
46
+ this.logger.debug(`[midway:redis] pubsub event received: channel=${channelName}, message=${message}`);
47
+ if (channelName !== channel)
48
+ return;
49
+ try {
50
+ // 变更时重新拉取全量数据
51
+ const keys = await this.scanKeys(`${this.options.prefix}${this.serviceName}:instance:*`);
52
+ setData(await this.fetchInstancesByKeys(keys));
53
+ }
54
+ catch (err) {
55
+ this.logger.error('[midway:redis] Error on service change:', err);
56
+ }
57
+ };
58
+ this.pubsub.subscribe(channel);
59
+ this.pubsub.on('message', handler);
60
+ // 提供取消订阅方法
61
+ this.unsubscribe = () => {
62
+ this.pubsub.off('message', handler);
63
+ this.pubsub.unsubscribe(channel);
64
+ };
65
+ }
66
+ async destroyListener() {
67
+ this.clearTTLRefresh();
68
+ if (this.unsubscribe) {
69
+ this.unsubscribe();
70
+ this.unsubscribe = null;
71
+ }
72
+ }
73
+ // 新增:上线时启动 TTL 刷新
74
+ async onlineInstance(instance) {
75
+ instance = this.instance = instance || this.instance;
76
+ this.instanceKey = this.getInstanceKey(instance.serviceName, instance.id);
77
+ const data = { ...instance, status: 'UP' };
78
+ const ttl = instance.ttl || this.options.ttl || 30;
79
+ this.logger.debug(`[midway:redis] set key: ${this.instanceKey}, value: ${JSON.stringify(data)}, ttl: ${ttl}`);
80
+ await this.client.set(this.instanceKey, JSON.stringify(data), 'EX', ttl);
81
+ this.startTTLRefresh();
82
+ const testKeys = await this.client.scan('0', 'MATCH', `${this.options.prefix}${instance.serviceName}:instance:*`, 'COUNT', 100);
83
+ this.logger.debug(`[midway:redis] after set, scan test: ${JSON.stringify(testKeys)}`);
84
+ }
85
+ // 新增:下线时清理 TTL 刷新
86
+ async offlineInstance(instance) {
87
+ instance = instance || this.instance;
88
+ this.clearTTLRefresh();
89
+ const instanceKey = this.getInstanceKey(instance.serviceName, instance.id);
90
+ await this.client.del(instanceKey);
91
+ }
92
+ /**
93
+ * 生成实例唯一 key
94
+ * 格式: <prefix><serviceName>:instance:<instanceId>
95
+ * 例: services:order:instance:abc123
96
+ */
97
+ getInstanceKey(serviceName, instanceId) {
98
+ return `${this.options.prefix}${serviceName}:instance:${instanceId}`;
99
+ }
100
+ startTTLRefresh() {
101
+ this.clearTTLRefresh();
102
+ if (!this.instance)
103
+ return;
104
+ const ttl = this.instance.ttl || this.options.ttl || 30;
105
+ const interval = Math.max(ttl * 500, 1000);
106
+ const refresh = async () => {
107
+ try {
108
+ if (this.instanceKey && this.instance) {
109
+ const data = { ...this.instance, status: 'UP' };
110
+ await this.client.set(this.instanceKey, JSON.stringify(data), 'EX', ttl);
111
+ }
112
+ }
113
+ catch (err) {
114
+ this.logger.error('[midway:redis] TTL refresh failed:', err);
115
+ }
116
+ this.ttlTimeout = setTimeout(refresh, interval);
117
+ };
118
+ refresh();
119
+ }
120
+ clearTTLRefresh() {
121
+ if (this.ttlTimeout) {
122
+ clearTimeout(this.ttlTimeout);
123
+ this.ttlTimeout = null;
124
+ }
125
+ }
126
+ /**
127
+ * 使用 SCAN 替代 KEYS,游标式遍历所有匹配的 key
128
+ */
129
+ async scanKeys(pattern, count) {
130
+ let cursor = '0';
131
+ let keys = [];
132
+ const scanCount = count || this.options.scanCount || 100;
133
+ do {
134
+ const [nextCursor, foundKeys] = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', scanCount);
135
+ cursor = nextCursor;
136
+ keys = keys.concat(foundKeys);
137
+ } while (cursor !== '0');
138
+ this.logger.debug(`[midway:redis] scanKeys pattern=${pattern}, found keys=${JSON.stringify(keys)}`);
139
+ return keys;
140
+ }
141
+ /**
142
+ * 批量获取实例 key 并反序列化为对象数组
143
+ */
144
+ async fetchInstancesByKeys(keys) {
145
+ if (keys.length === 0)
146
+ return [];
147
+ const values = await this.client.mget(keys);
148
+ return values
149
+ .map(value => {
150
+ try {
151
+ return JSON.parse(value);
152
+ }
153
+ catch {
154
+ return null;
155
+ }
156
+ })
157
+ .filter(Boolean);
158
+ }
159
+ }
160
+ class RedisServiceDiscoverClient extends core_1.ServiceDiscoveryClient {
161
+ redis;
162
+ serviceDiscoveryOptions;
163
+ logger;
164
+ getListener;
165
+ registeredInstance = null;
166
+ onlineInstanceData = null;
167
+ constructor(redis, serviceDiscoveryOptions, logger, getListener) {
168
+ super(redis, serviceDiscoveryOptions);
169
+ this.redis = redis;
170
+ this.serviceDiscoveryOptions = serviceDiscoveryOptions;
171
+ this.logger = logger;
172
+ this.getListener = getListener;
173
+ }
174
+ async register(instance) {
175
+ this.registeredInstance = instance;
176
+ if (!instance.serviceName) {
177
+ throw new core_1.MidwayConfigMissingError('instance.serviceName is required when register service in redis');
178
+ }
179
+ // 注册时默认上线
180
+ await this.online();
181
+ this.logger.info(`[midway:redis] register instance: ${instance.id} for service: ${instance.serviceName}`);
182
+ }
183
+ async deregister() {
184
+ if (this.onlineInstanceData) {
185
+ await this.offline();
186
+ }
187
+ if (this.registeredInstance) {
188
+ // 发布服务变更消息
189
+ await this.client.publish(`service:change:${this.registeredInstance.serviceName}`, JSON.stringify({
190
+ type: 'deregister',
191
+ service: this.registeredInstance.serviceName,
192
+ instance: this.registeredInstance,
193
+ }));
194
+ this.logger.info(`[midway:redis] deregister instance: ${this.registeredInstance.id} for service: ${this.registeredInstance.serviceName}`);
195
+ this.registeredInstance = null;
196
+ }
197
+ }
198
+ async online() {
199
+ this.logger.debug('[midway:redis] online() called');
200
+ this.logger.debug(`[midway:redis] registeredInstance: ${JSON.stringify(this.registeredInstance)}`);
201
+ if (!this.registeredInstance) {
202
+ this.logger.error('[midway:redis] online() failed: No instance registered.');
203
+ throw new Error('No instance registered, cannot online.');
204
+ }
205
+ // 已经上线则忽略
206
+ if (this.onlineInstanceData) {
207
+ this.logger.debug('[midway:redis] online() ignored: already online.');
208
+ return;
209
+ }
210
+ const listener = await this.getListener(this.registeredInstance.serviceName);
211
+ await listener.onlineInstance(this.registeredInstance);
212
+ this.onlineInstanceData = this.registeredInstance;
213
+ this.logger.info(`[midway:redis] online() success: instance ${this.registeredInstance.id} for service ${this.registeredInstance.serviceName}`);
214
+ // 发布上线消息
215
+ await this.client.publish(`service:change:${this.registeredInstance.serviceName}`, JSON.stringify({
216
+ type: 'online',
217
+ service: this.registeredInstance.serviceName,
218
+ instance: this.registeredInstance,
219
+ }));
220
+ }
221
+ async offline() {
222
+ this.logger.debug('[midway:redis] offline() called');
223
+ this.logger.debug(`[midway:redis] onlineInstanceData: ${JSON.stringify(this.onlineInstanceData)}`);
224
+ // 已经下线则忽略
225
+ if (!this.onlineInstanceData) {
226
+ this.logger.info('[midway:redis] offline() ignored: already offline.');
227
+ return;
228
+ }
229
+ const listener = await this.getListener(this.onlineInstanceData.serviceName);
230
+ await listener.offlineInstance(this.onlineInstanceData);
231
+ this.logger.info(`[midway:redis] offline() success: instance ${this.onlineInstanceData.id} for service ${this.onlineInstanceData.serviceName}`);
232
+ // 发布下线消息
233
+ await this.client.publish(`service:change:${this.onlineInstanceData.serviceName}`, JSON.stringify({
234
+ type: 'offline',
235
+ service: this.onlineInstanceData.serviceName,
236
+ instance: this.onlineInstanceData,
237
+ }));
238
+ this.onlineInstanceData = null;
239
+ }
240
+ async beforeStop() { }
241
+ }
242
+ exports.RedisServiceDiscoverClient = RedisServiceDiscoverClient;
243
+ let RedisServiceDiscovery = class RedisServiceDiscovery extends core_1.ServiceDiscovery {
244
+ redisServiceFactory;
245
+ configService;
246
+ coreLogger;
247
+ redisServiceDiscoveryOptions;
248
+ listenerStore = new Map();
249
+ pubsub;
250
+ async init() {
251
+ this.redisServiceDiscoveryOptions = this.configService.getConfiguration('redis.serviceDiscovery', {});
252
+ this.redisServiceDiscoveryOptions.prefix =
253
+ this.redisServiceDiscoveryOptions.prefix || 'services:';
254
+ }
255
+ getServiceClient() {
256
+ return this.redisServiceFactory.get(this.redisServiceDiscoveryOptions.serviceDiscoveryClient ||
257
+ this.redisServiceFactory.getDefaultClientName() ||
258
+ 'default');
259
+ }
260
+ createServiceDiscoverClientImpl(options) {
261
+ return new RedisServiceDiscoverClient(this.getServiceClient(), options, this.coreLogger, serviceName => this.getListener(serviceName));
262
+ }
263
+ getDefaultServiceDiscoveryOptions() {
264
+ return this.redisServiceDiscoveryOptions;
265
+ }
266
+ async getListener(serviceName) {
267
+ if (!this.pubsub) {
268
+ this.pubsub = this.getServiceClient().duplicate();
269
+ }
270
+ // 日志:打印当前请求的 serviceName
271
+ this.coreLogger.debug(`[midway:redis] getListener called for serviceName: ${serviceName}`);
272
+ // 日志:打印当前 listenerStore keys
273
+ this.coreLogger.debug(`[midway:redis] listenerStore keys: ${Array.from(this.listenerStore.keys()).join(',')}`);
274
+ if (!this.listenerStore.has(serviceName)) {
275
+ this.coreLogger.debug(`[midway:redis] listener for ${serviceName} not found, creating new listener.`);
276
+ const listener = new RedisDataListener(serviceName, this.getServiceClient(), this.pubsub, this.redisServiceDiscoveryOptions, this.coreLogger);
277
+ this.listenerStore.set(serviceName, listener);
278
+ await listener.init();
279
+ this.coreLogger.debug(`[midway:redis] listener for ${serviceName} initialized.`);
280
+ }
281
+ else {
282
+ this.coreLogger.debug(`[midway:redis] listener for ${serviceName} found in cache.`);
283
+ }
284
+ return this.listenerStore.get(serviceName);
285
+ }
286
+ async getInstances(serviceName) {
287
+ // 优先从 listener 的缓存获取数据
288
+ const listener = await this.getListener(serviceName);
289
+ return listener.getData();
290
+ }
291
+ async beforeStop() {
292
+ await Promise.all(Array.from(this.listenerStore.values()).map(listener => listener.destroyListener()));
293
+ this.listenerStore.clear();
294
+ if (this.pubsub) {
295
+ await this.pubsub.unsubscribe();
296
+ await this.pubsub.quit();
297
+ this.pubsub = null;
298
+ }
299
+ }
300
+ };
301
+ exports.RedisServiceDiscovery = RedisServiceDiscovery;
302
+ __decorate([
303
+ (0, core_1.Inject)(),
304
+ __metadata("design:type", manager_1.RedisServiceFactory)
305
+ ], RedisServiceDiscovery.prototype, "redisServiceFactory", void 0);
306
+ __decorate([
307
+ (0, core_1.Inject)(),
308
+ __metadata("design:type", core_1.MidwayConfigService)
309
+ ], RedisServiceDiscovery.prototype, "configService", void 0);
310
+ __decorate([
311
+ (0, core_1.Logger)(),
312
+ __metadata("design:type", Object)
313
+ ], RedisServiceDiscovery.prototype, "coreLogger", void 0);
314
+ __decorate([
315
+ (0, core_1.Init)(),
316
+ __metadata("design:type", Function),
317
+ __metadata("design:paramtypes", []),
318
+ __metadata("design:returntype", Promise)
319
+ ], RedisServiceDiscovery.prototype, "init", null);
320
+ exports.RedisServiceDiscovery = RedisServiceDiscovery = __decorate([
321
+ (0, core_1.Singleton)()
322
+ ], RedisServiceDiscovery);
323
+ //# 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
@@ -14,39 +14,43 @@ const core_1 = require("@midwayjs/core");
14
14
  const ioredis_1 = require("ioredis");
15
15
  const assert = require("assert");
16
16
  let RedisServiceFactory = class RedisServiceFactory extends core_1.ServiceFactory {
17
+ redisConfig;
17
18
  async init() {
18
- await this.initClients(this.redisConfig);
19
+ await this.initClients(this.redisConfig, {
20
+ concurrent: true,
21
+ });
19
22
  }
20
- async createClient(config) {
23
+ logger;
24
+ async createClient(config, name) {
21
25
  let client;
22
26
  if (config.cluster === true) {
23
- assert.ok(config.nodes && config.nodes.length !== 0, '[midway:redis] cluster nodes configuration is required when use cluster redis');
27
+ assert.ok(config.nodes && config.nodes.length !== 0, `[midway:redis] client(${name}) cluster nodes configuration is required when use cluster redis`);
24
28
  config.nodes.forEach(client => {
25
- assert.ok(client.host && client.port, `[midway:redis] 'host: ${client.host}', 'port: ${client.port}' are required on config`);
29
+ assert.ok(client.host && client.port, `[midway:redis] client(${name}) 'host: ${client.host}', 'port: ${client.port}' are required on config`);
26
30
  });
27
31
  client = new ioredis_1.default.Cluster(config.nodes, config);
28
32
  this.logger.info('[midway:redis] cluster is connecting');
29
33
  }
30
34
  else if (config.sentinels) {
31
- assert.ok(config.sentinels && config.sentinels.length !== 0, '[midway:redis] sentinels configuration is required when use redis sentinel');
35
+ assert.ok(config.sentinels && config.sentinels.length !== 0, `[midway:redis] client(${name}) sentinels configuration is required when use redis sentinel`);
32
36
  config.sentinels.forEach(sentinel => {
33
- assert.ok(sentinel.host && sentinel.port, `[midway:redis] 'host: ${sentinel.host}', 'port: ${sentinel.port}' are required on config`);
37
+ assert.ok(sentinel.host && sentinel.port, `[midway:redis] client(${name}) 'host: ${sentinel.host}', 'port: ${sentinel.port}' are required on config`);
34
38
  });
35
39
  client = new ioredis_1.default(config);
36
- this.logger.info('[midway:redis] sentinel is connecting');
40
+ this.logger.info(`[midway:redis] client(${name}) sentinel is connecting`);
37
41
  }
38
42
  else {
39
- assert.ok(config.host && config.port, `[midway:redis] 'host: ${config.host}', 'port: ${config.port}' are required on config`);
43
+ assert.ok(config.host && config.port, `[midway:redis] client(${name}) 'host: ${config.host}', 'port: ${config.port}' are required on config`);
40
44
  client = new ioredis_1.default(config);
41
- this.logger.info('[midway:redis] server is connecting redis://:***@%s:%s', config.host, config.port);
45
+ this.logger.info(`[midway:redis] client(${name}) server is connecting redis://:***@${config.host}:${config.port}`);
42
46
  }
43
47
  await new Promise((resolve, reject) => {
44
48
  client.on('ready', () => {
45
- this.logger.info('[midway:redis] client connect success');
49
+ this.logger.info(`[midway:redis] client(${name}) connect success`);
46
50
  resolve();
47
51
  });
48
52
  client.on('error', err => {
49
- this.logger.error('[midway:redis] client error: %s', err);
53
+ this.logger.error(`[midway:redis] client(${name}) error: ${err}`);
50
54
  reject(err);
51
55
  });
52
56
  });
@@ -55,17 +59,18 @@ let RedisServiceFactory = class RedisServiceFactory extends core_1.ServiceFactor
55
59
  getName() {
56
60
  return 'redis';
57
61
  }
58
- async destroyClient(redisInstance) {
62
+ async destroyClient(redisInstance, name) {
59
63
  try {
60
64
  if (redisInstance) {
61
65
  const canQuit = !['end', 'close'].includes(redisInstance.status);
62
66
  if (canQuit) {
63
67
  await redisInstance.quit();
68
+ this.logger.info(`[midway:redis] client(${name}) quit success`);
64
69
  }
65
70
  }
66
71
  }
67
72
  catch (error) {
68
- this.logger.error('[midway:redis] Redis quit failed.', error);
73
+ this.logger.error(`[midway:redis] client(${name}) Redis quit failed.`, error);
69
74
  }
70
75
  }
71
76
  };
@@ -89,6 +94,8 @@ exports.RedisServiceFactory = RedisServiceFactory = __decorate([
89
94
  (0, core_1.Scope)(core_1.ScopeEnum.Singleton)
90
95
  ], RedisServiceFactory);
91
96
  let RedisService = class RedisService {
97
+ serviceFactory;
98
+ instance;
92
99
  async init() {
93
100
  this.instance = this.serviceFactory.get(this.serviceFactory.getDefaultClientName?.() || 'default');
94
101
  if (!this.instance) {
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": "4.0.0-alpha.1",
4
+ "version": "4.0.0-beta.10",
5
5
  "main": "dist/index.js",
6
6
  "typings": "index.d.ts",
7
7
  "files": [
@@ -10,11 +10,11 @@
10
10
  "index.d.ts"
11
11
  ],
12
12
  "devDependencies": {
13
- "@midwayjs/core": "^4.0.0-alpha.1",
14
- "@midwayjs/mock": "^4.0.0-alpha.1"
13
+ "@midwayjs/core": "^4.0.0-beta.10",
14
+ "@midwayjs/mock": "^4.0.0-beta.10"
15
15
  },
16
16
  "dependencies": {
17
- "ioredis": "5.4.1"
17
+ "ioredis": "5.4.2"
18
18
  },
19
19
  "keywords": [
20
20
  "redis"
@@ -29,11 +29,11 @@
29
29
  "lint": "mwts check"
30
30
  },
31
31
  "engines": {
32
- "node": ">=12"
32
+ "node": ">=20"
33
33
  },
34
34
  "repository": {
35
35
  "type": "git",
36
36
  "url": "https://github.com/midwayjs/midway.git"
37
37
  },
38
- "gitHead": "14bb4da91805a1cf52f190c0d37a74b395dd6372"
38
+ "gitHead": "1b1856629913703f67304155aaf611ec936a81ac"
39
39
  }