@midwayjs/core 4.0.0-alpha.1 → 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.
Files changed (59) hide show
  1. package/README.md +1 -1
  2. package/dist/baseFramework.d.ts +7 -4
  3. package/dist/baseFramework.js +12 -10
  4. package/dist/common/applicationManager.js +5 -1
  5. package/dist/common/dataListener.d.ts +5 -3
  6. package/dist/common/dataListener.js +12 -3
  7. package/dist/common/dataSourceManager.d.ts +18 -9
  8. package/dist/common/dataSourceManager.js +121 -71
  9. package/dist/common/serviceDiscovery/healthCheck.d.ts +66 -0
  10. package/dist/common/serviceDiscovery/healthCheck.js +207 -0
  11. package/dist/common/serviceDiscovery/loadBalancer.d.ts +21 -0
  12. package/dist/common/serviceDiscovery/loadBalancer.js +51 -0
  13. package/dist/common/serviceDiscovery/serviceDiscovery.d.ts +59 -0
  14. package/dist/common/serviceDiscovery/serviceDiscovery.js +104 -0
  15. package/dist/common/serviceFactory.d.ts +5 -2
  16. package/dist/common/serviceFactory.js +43 -8
  17. package/dist/config/config.default.js +3 -0
  18. package/dist/context/container.d.ts +4 -3
  19. package/dist/context/container.js +6 -2
  20. package/dist/context/definitionRegistry.d.ts +2 -0
  21. package/dist/context/definitionRegistry.js +9 -11
  22. package/dist/context/dynamicContainer.d.ts +17 -0
  23. package/dist/context/dynamicContainer.js +202 -0
  24. package/dist/context/managedResolverFactory.d.ts +1 -2
  25. package/dist/context/managedResolverFactory.js +14 -7
  26. package/dist/context/requestContainer.d.ts +1 -0
  27. package/dist/context/requestContainer.js +3 -0
  28. package/dist/decorator/metadataManager.d.ts +6 -2
  29. package/dist/definitions/objectCreator.js +3 -1
  30. package/dist/error/framework.d.ts +1 -1
  31. package/dist/error/framework.js +4 -2
  32. package/dist/error/http.d.ts +7 -0
  33. package/dist/error/http.js +11 -1
  34. package/dist/functional/configuration.d.ts +6 -6
  35. package/dist/functional/configuration.js +10 -10
  36. package/dist/functional/hooks.d.ts +3 -1
  37. package/dist/functional/hooks.js +11 -1
  38. package/dist/index.d.ts +5 -1
  39. package/dist/index.js +8 -2
  40. package/dist/interface.d.ts +180 -20
  41. package/dist/interface.js +15 -1
  42. package/dist/service/configService.d.ts +1 -1
  43. package/dist/service/configService.js +3 -2
  44. package/dist/service/healthService.d.ts +2 -0
  45. package/dist/service/healthService.js +15 -4
  46. package/dist/service/informationService.d.ts +3 -0
  47. package/dist/service/informationService.js +10 -0
  48. package/dist/service/lifeCycleService.d.ts +13 -7
  49. package/dist/service/lifeCycleService.js +49 -32
  50. package/dist/setup.js +8 -1
  51. package/dist/util/index.d.ts +2 -17
  52. package/dist/util/index.js +8 -67
  53. package/dist/util/network.d.ts +10 -0
  54. package/dist/util/network.js +40 -0
  55. package/dist/util/pathFileUtil.d.ts +1 -1
  56. package/dist/util/pathFileUtil.js +2 -2
  57. package/dist/util/timeout.d.ts +57 -0
  58. package/dist/util/timeout.js +144 -0
  59. package/package.json +3 -3
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServiceDiscoveryHealthCheckFactory = exports.TCPHealthCheck = exports.HTTPHealthCheck = exports.TTLHealthCheck = exports.AbstractHealthCheck = void 0;
4
+ const httpclient_1 = require("../../util/httpclient");
5
+ const error_1 = require("../../error");
6
+ const net = require("net");
7
+ /**
8
+ * 抽象健康检查类
9
+ */
10
+ class AbstractHealthCheck {
11
+ constructor(options) {
12
+ this.lastCheckTime = 0;
13
+ this.lastCheckResult = null;
14
+ // 设置默认值
15
+ const defaultOptions = {
16
+ interval: 10000, // 默认10秒
17
+ timeout: 5000, // 默认5秒
18
+ maxRetries: 3, // 默认3次
19
+ retryInterval: 1000, // 默认1秒
20
+ };
21
+ // 合并默认值和传入的选项
22
+ this.options = {
23
+ ...defaultOptions,
24
+ ...options,
25
+ };
26
+ }
27
+ /**
28
+ * 是否需要检查
29
+ * 根据检查间隔判断是否需要执行新的检查
30
+ */
31
+ shouldCheck() {
32
+ const now = Date.now();
33
+ return now - this.lastCheckTime >= this.options.interval;
34
+ }
35
+ /**
36
+ * 获取最后一次检查结果
37
+ */
38
+ getLastCheckResult() {
39
+ return this.lastCheckResult;
40
+ }
41
+ /**
42
+ * 更新检查结果
43
+ */
44
+ updateCheckResult(result) {
45
+ this.lastCheckTime = Date.now();
46
+ this.lastCheckResult = result;
47
+ }
48
+ }
49
+ exports.AbstractHealthCheck = AbstractHealthCheck;
50
+ /**
51
+ * TTL 健康检查实现
52
+ * 用于 Redis/ETCD 等基于 TTL 的服务发现
53
+ */
54
+ class TTLHealthCheck extends AbstractHealthCheck {
55
+ constructor(options) {
56
+ super(options);
57
+ this.ttl = options?.ttl;
58
+ }
59
+ async check(instance) {
60
+ const now = Date.now();
61
+ const lastUpdate = instance.getMetadata()?.lastUpdate || 0;
62
+ const timeSinceLastUpdate = now - lastUpdate;
63
+ if (timeSinceLastUpdate > this.ttl * 1000) {
64
+ return {
65
+ status: 'critical',
66
+ message: 'Service instance TTL expired',
67
+ timestamp: now,
68
+ };
69
+ }
70
+ return {
71
+ status: 'passing',
72
+ timestamp: now,
73
+ };
74
+ }
75
+ }
76
+ exports.TTLHealthCheck = TTLHealthCheck;
77
+ /**
78
+ * HTTP 健康检查实现
79
+ * 用于支持 HTTP 检查的服务发现
80
+ */
81
+ class HTTPHealthCheck extends AbstractHealthCheck {
82
+ constructor(options) {
83
+ super(options);
84
+ this.checkUrl = options.url;
85
+ this.httpOptions = options;
86
+ this.httpClient = new httpclient_1.HttpClient({
87
+ timeout: options.timeout || 5000,
88
+ });
89
+ }
90
+ async check(instance) {
91
+ const now = Date.now();
92
+ let retries = 0;
93
+ let lastError = null;
94
+ while (retries < this.httpOptions.maxRetries) {
95
+ try {
96
+ const response = await this.httpClient.request(this.checkUrl, {
97
+ method: this.httpOptions.method || 'GET',
98
+ headers: this.httpOptions.headers,
99
+ timeout: this.httpOptions.timeout,
100
+ });
101
+ if (response.status === (this.httpOptions.expectedStatus || 200)) {
102
+ return {
103
+ status: 'passing',
104
+ timestamp: now,
105
+ };
106
+ }
107
+ lastError = new error_1.MidwayCommonError(`HTTP health check failed with status ${response.status}`);
108
+ retries++;
109
+ if (retries < this.httpOptions.maxRetries) {
110
+ await new Promise(resolve => setTimeout(resolve, this.httpOptions.retryInterval));
111
+ }
112
+ }
113
+ catch (error) {
114
+ lastError = new error_1.MidwayCommonError(`HTTP health check error: ${error.message}`);
115
+ retries++;
116
+ if (retries < this.httpOptions.maxRetries) {
117
+ await new Promise(resolve => setTimeout(resolve, this.httpOptions.retryInterval));
118
+ }
119
+ }
120
+ }
121
+ return {
122
+ status: 'critical',
123
+ message: lastError?.message || 'Health check failed after all retries',
124
+ timestamp: now,
125
+ };
126
+ }
127
+ }
128
+ exports.HTTPHealthCheck = HTTPHealthCheck;
129
+ /**
130
+ * TCP 健康检查实现
131
+ * 用于支持 TCP 检查的服务发现
132
+ */
133
+ class TCPHealthCheck extends AbstractHealthCheck {
134
+ constructor(options) {
135
+ super(options);
136
+ this.host = options.host;
137
+ this.port = options.port;
138
+ this.tcpOptions = options;
139
+ }
140
+ async check(instance) {
141
+ const now = Date.now();
142
+ let retries = 0;
143
+ let lastError = null;
144
+ while (retries < this.tcpOptions.maxRetries) {
145
+ try {
146
+ const socket = new Promise((resolve, reject) => {
147
+ const client = net.createConnection(this.port, this.host, () => {
148
+ client.end();
149
+ resolve(true);
150
+ });
151
+ client.on('error', error => {
152
+ client.end();
153
+ reject(new error_1.MidwayCommonError(`TCP connection failed: ${error.message}`));
154
+ });
155
+ client.setTimeout(this.tcpOptions.timeout, () => {
156
+ client.end();
157
+ reject(new error_1.MidwayCommonError('TCP connection timeout'));
158
+ });
159
+ });
160
+ await socket;
161
+ return {
162
+ status: 'passing',
163
+ timestamp: now,
164
+ };
165
+ }
166
+ catch (error) {
167
+ lastError =
168
+ error instanceof error_1.MidwayCommonError
169
+ ? error
170
+ : new error_1.MidwayCommonError(`TCP health check error: ${error.message}`);
171
+ retries++;
172
+ if (retries < this.tcpOptions.maxRetries) {
173
+ await new Promise(resolve => setTimeout(resolve, this.tcpOptions.retryInterval));
174
+ }
175
+ }
176
+ }
177
+ return {
178
+ status: 'critical',
179
+ message: lastError?.message || 'TCP health check failed after all retries',
180
+ timestamp: now,
181
+ };
182
+ }
183
+ }
184
+ exports.TCPHealthCheck = TCPHealthCheck;
185
+ /**
186
+ * 健康检查工厂
187
+ */
188
+ class ServiceDiscoveryHealthCheckFactory {
189
+ static create(type, options) {
190
+ switch (type) {
191
+ case 'self':
192
+ return undefined;
193
+ case 'ttl':
194
+ return new TTLHealthCheck(options);
195
+ case 'http':
196
+ return new HTTPHealthCheck(options);
197
+ case 'tcp':
198
+ return new TCPHealthCheck(options);
199
+ case 'custom':
200
+ return options;
201
+ default:
202
+ throw new error_1.MidwayCommonError(`Unsupported health check type: ${type}`);
203
+ }
204
+ }
205
+ }
206
+ exports.ServiceDiscoveryHealthCheckFactory = ServiceDiscoveryHealthCheckFactory;
207
+ //# sourceMappingURL=healthCheck.js.map
@@ -0,0 +1,21 @@
1
+ import { ILoadBalancer, LoadBalancerType } from '../../interface';
2
+ /**
3
+ * 随机负载均衡策略
4
+ */
5
+ export declare class RandomLoadBalance<ServiceInstance> implements ILoadBalancer<ServiceInstance> {
6
+ select(instances: ServiceInstance[]): ServiceInstance;
7
+ }
8
+ /**
9
+ * 轮询负载均衡策略
10
+ */
11
+ export declare class RoundRobinLoadBalancer<ServiceInstance> implements ILoadBalancer<ServiceInstance> {
12
+ private currentIndex;
13
+ select(instances: ServiceInstance[]): ServiceInstance;
14
+ }
15
+ /**
16
+ * 负载均衡工厂
17
+ */
18
+ export declare class LoadBalancerFactory {
19
+ static create<ServiceInstance>(type: LoadBalancerType): ILoadBalancer<ServiceInstance>;
20
+ }
21
+ //# sourceMappingURL=loadBalancer.d.ts.map
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoadBalancerFactory = exports.RoundRobinLoadBalancer = exports.RandomLoadBalance = void 0;
4
+ const interface_1 = require("../../interface");
5
+ /**
6
+ * 随机负载均衡策略
7
+ */
8
+ class RandomLoadBalance {
9
+ select(instances) {
10
+ if (!instances.length) {
11
+ throw new Error('No available instances');
12
+ }
13
+ const index = Math.floor(Math.random() * instances.length);
14
+ return instances[index];
15
+ }
16
+ }
17
+ exports.RandomLoadBalance = RandomLoadBalance;
18
+ /**
19
+ * 轮询负载均衡策略
20
+ */
21
+ class RoundRobinLoadBalancer {
22
+ constructor() {
23
+ this.currentIndex = 0;
24
+ }
25
+ select(instances) {
26
+ if (!instances.length) {
27
+ throw new Error('No available instances');
28
+ }
29
+ const instance = instances[this.currentIndex];
30
+ this.currentIndex = (this.currentIndex + 1) % instances.length;
31
+ return instance;
32
+ }
33
+ }
34
+ exports.RoundRobinLoadBalancer = RoundRobinLoadBalancer;
35
+ /**
36
+ * 负载均衡工厂
37
+ */
38
+ class LoadBalancerFactory {
39
+ static create(type) {
40
+ switch (type) {
41
+ case interface_1.LoadBalancerType.RANDOM:
42
+ return new RandomLoadBalance();
43
+ case interface_1.LoadBalancerType.ROUND_ROBIN:
44
+ return new RoundRobinLoadBalancer();
45
+ default:
46
+ throw new Error(`Unsupported load balancer type: ${type}`);
47
+ }
48
+ }
49
+ }
50
+ exports.LoadBalancerFactory = LoadBalancerFactory;
51
+ //# sourceMappingURL=loadBalancer.js.map
@@ -0,0 +1,59 @@
1
+ import { IServiceDiscoveryClient, ServiceDiscoveryOptions, ILoadBalancer, DefaultInstanceMetadata } from '../../interface';
2
+ import { LoadBalancerType } from '../../interface';
3
+ export declare abstract class ServiceDiscoveryClient<Client, ServiceDiscoveryConfigOptions extends ServiceDiscoveryOptions<QueryServiceInstance>, RegisterServiceInstance, QueryServiceInstance = RegisterServiceInstance> implements IServiceDiscoveryClient<QueryServiceInstance> {
4
+ protected options: ServiceDiscoveryConfigOptions;
5
+ protected instance?: RegisterServiceInstance;
6
+ protected client: Client;
7
+ protected constructor(client: Client, serviceDiscoveryOptions: ServiceDiscoveryConfigOptions);
8
+ private _defaultMeta;
9
+ get defaultMeta(): DefaultInstanceMetadata;
10
+ private getDefaultInstanceMeta;
11
+ getSelfInstance(): RegisterServiceInstance;
12
+ abstract beforeStop(): Promise<void>;
13
+ /**
14
+ * 停止服务发现
15
+ */
16
+ stop(): Promise<void>;
17
+ /**
18
+ * 注册服务实例
19
+ */
20
+ abstract register(instance: RegisterServiceInstance): Promise<void>;
21
+ /**
22
+ * 注销服务实例
23
+ */
24
+ abstract deregister(): Promise<void>;
25
+ /**
26
+ * 上线服务实例
27
+ */
28
+ abstract online(): Promise<void>;
29
+ /**
30
+ * 下线服务实例
31
+ */
32
+ abstract offline(): Promise<void>;
33
+ }
34
+ /**
35
+ * 服务发现抽象类
36
+ */
37
+ export declare abstract class ServiceDiscovery<Client, ServiceDiscoveryConfigOptions extends ServiceDiscoveryOptions<QueryServiceInstance>, RegisterServiceInstance, QueryServiceInstance = RegisterServiceInstance, GetInstanceOptions = RegisterServiceInstance> {
38
+ protected serviceDiscoveryClientStore: Set<ServiceDiscoveryClient<Client, ServiceDiscoveryConfigOptions, RegisterServiceInstance, QueryServiceInstance>>;
39
+ protected abstract getServiceClient(): Client;
40
+ protected loadBalancer: ILoadBalancer<QueryServiceInstance>;
41
+ createClient(options?: ServiceDiscoveryOptions<QueryServiceInstance>): ServiceDiscoveryClient<Client, ServiceDiscoveryConfigOptions, RegisterServiceInstance, QueryServiceInstance>;
42
+ protected abstract createServiceDiscoverClientImpl(options: ServiceDiscoveryOptions<QueryServiceInstance>): ServiceDiscoveryClient<Client, ServiceDiscoveryConfigOptions, RegisterServiceInstance, QueryServiceInstance>;
43
+ protected abstract getDefaultServiceDiscoveryOptions(): ServiceDiscoveryConfigOptions;
44
+ protected beforeStop(): Promise<void>;
45
+ /**
46
+ * 获取可用服务列表
47
+ */
48
+ abstract getInstances(options: GetInstanceOptions): Promise<QueryServiceInstance[]>;
49
+ /**
50
+ * 获取一个可用服务实例(带负载均衡)
51
+ */
52
+ getInstance(options: GetInstanceOptions): Promise<QueryServiceInstance>;
53
+ /**
54
+ * 设置负载均衡策略
55
+ */
56
+ setLoadBalancer(type: LoadBalancerType | ILoadBalancer<QueryServiceInstance>): void;
57
+ protected destroy(): Promise<void>;
58
+ }
59
+ //# sourceMappingURL=serviceDiscovery.d.ts.map
@@ -0,0 +1,104 @@
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.ServiceDiscovery = exports.ServiceDiscoveryClient = void 0;
13
+ const decorator_1 = require("../../decorator");
14
+ const loadBalancer_1 = require("./loadBalancer");
15
+ const interface_1 = require("../../interface");
16
+ const network_1 = require("../../util/network");
17
+ const extend_1 = require("../../util/extend");
18
+ class ServiceDiscoveryClient {
19
+ constructor(client, serviceDiscoveryOptions) {
20
+ this.client = client;
21
+ this.options =
22
+ serviceDiscoveryOptions ?? {};
23
+ }
24
+ get defaultMeta() {
25
+ if (!this._defaultMeta) {
26
+ this._defaultMeta = this.getDefaultInstanceMeta();
27
+ }
28
+ return this._defaultMeta;
29
+ }
30
+ getDefaultInstanceMeta() {
31
+ return {
32
+ id: `${network_1.NetworkUtils.getHostname()}-${process.pid}`,
33
+ serviceName: `${network_1.NetworkUtils.getHostname()}`,
34
+ host: network_1.NetworkUtils.getIpv4Address(),
35
+ port: 0,
36
+ metadata: {},
37
+ };
38
+ }
39
+ getSelfInstance() {
40
+ return this.instance;
41
+ }
42
+ /**
43
+ * 停止服务发现
44
+ */
45
+ async stop() {
46
+ await this.beforeStop();
47
+ if (this.instance) {
48
+ return this.deregister();
49
+ }
50
+ }
51
+ }
52
+ exports.ServiceDiscoveryClient = ServiceDiscoveryClient;
53
+ /**
54
+ * 服务发现抽象类
55
+ */
56
+ class ServiceDiscovery {
57
+ constructor() {
58
+ this.serviceDiscoveryClientStore = new Set();
59
+ }
60
+ createClient(options) {
61
+ const serviceDiscoveryOption = (0, extend_1.extend)({}, options, this.getDefaultServiceDiscoveryOptions());
62
+ const client = this.createServiceDiscoverClientImpl(serviceDiscoveryOption);
63
+ this.serviceDiscoveryClientStore.add(client);
64
+ return client;
65
+ }
66
+ async beforeStop() { }
67
+ /**
68
+ * 获取一个可用服务实例(带负载均衡)
69
+ */
70
+ async getInstance(options) {
71
+ const instances = await this.getInstances(options);
72
+ if (!this.loadBalancer) {
73
+ this.setLoadBalancer(this.getDefaultServiceDiscoveryOptions()?.loadBalancer ??
74
+ interface_1.LoadBalancerType.ROUND_ROBIN);
75
+ }
76
+ return this.loadBalancer.select(instances);
77
+ }
78
+ /**
79
+ * 设置负载均衡策略
80
+ */
81
+ setLoadBalancer(type) {
82
+ if (typeof type === 'string') {
83
+ this.loadBalancer = loadBalancer_1.LoadBalancerFactory.create(type);
84
+ }
85
+ else {
86
+ this.loadBalancer = type;
87
+ }
88
+ }
89
+ async destroy() {
90
+ await this.beforeStop();
91
+ for (const client of this.serviceDiscoveryClientStore) {
92
+ await client.stop();
93
+ }
94
+ this.serviceDiscoveryClientStore.clear();
95
+ }
96
+ }
97
+ exports.ServiceDiscovery = ServiceDiscovery;
98
+ __decorate([
99
+ (0, decorator_1.Destroy)(),
100
+ __metadata("design:type", Function),
101
+ __metadata("design:paramtypes", []),
102
+ __metadata("design:returntype", Promise)
103
+ ], ServiceDiscovery.prototype, "destroy", null);
104
+ //# sourceMappingURL=serviceDiscovery.js.map
@@ -8,10 +8,13 @@ export declare abstract class ServiceFactory<T> implements IServiceFactory<T> {
8
8
  protected clientPriority: Record<string, string>;
9
9
  protected options: {};
10
10
  protected priorityManager: MidwayPriorityManager;
11
- protected initClients(options?: any): Promise<void>;
11
+ private creatingClients;
12
+ protected initClients(options?: any, initOptions?: {
13
+ concurrent?: boolean;
14
+ }): Promise<void>;
12
15
  get<U = T>(id?: string): U;
13
16
  has(id: string): boolean;
14
- createInstance(config: any, clientName?: any): Promise<T | undefined>;
17
+ createInstance(config: any, clientName?: string): Promise<any>;
15
18
  abstract getName(): string;
16
19
  protected abstract createClient(config: any, clientName: any): Promise<T | void> | (T | void);
17
20
  protected destroyClient(client: T, clientName?: string): Promise<void>;
@@ -13,6 +13,7 @@ exports.ServiceFactory = void 0;
13
13
  const extend_1 = require("../util/extend");
14
14
  const priorityManager_1 = require("./priorityManager");
15
15
  const decorator_1 = require("../decorator");
16
+ const types_1 = require("../util/types");
16
17
  /**
17
18
  * 多客户端工厂实现
18
19
  */
@@ -20,8 +21,10 @@ class ServiceFactory {
20
21
  constructor() {
21
22
  this.clients = new Map();
22
23
  this.options = {};
24
+ // for multi client with initialization
25
+ this.creatingClients = new Map();
23
26
  }
24
- async initClients(options = {}) {
27
+ async initClients(options = {}, initOptions = {}) {
25
28
  this.options = options;
26
29
  // merge options.client to options.clients['default']
27
30
  if (options.client) {
@@ -29,10 +32,17 @@ class ServiceFactory {
29
32
  options.clients['default'] = options.clients['default'] || {};
30
33
  (0, extend_1.extend)(true, options.clients['default'], options.client);
31
34
  }
32
- // multi client
33
35
  if (options.clients) {
34
- for (const id of Object.keys(options.clients)) {
35
- await this.createInstance(options.clients[id], id);
36
+ const entries = Object.entries(options.clients);
37
+ if (initOptions.concurrent) {
38
+ // multi client with concurrent initialization
39
+ await Promise.all(entries.map(([id, config]) => this.createInstance(config, id)));
40
+ }
41
+ else {
42
+ // multi client with serial initialization
43
+ for (const [id, config] of entries) {
44
+ await this.createInstance(config, id);
45
+ }
36
46
  }
37
47
  }
38
48
  // set priority
@@ -45,21 +55,46 @@ class ServiceFactory {
45
55
  return this.clients.has(id);
46
56
  }
47
57
  async createInstance(config, clientName) {
58
+ if (clientName) {
59
+ if (this.has(clientName)) {
60
+ return this.get(clientName);
61
+ }
62
+ if (this.creatingClients.has(clientName)) {
63
+ return this.creatingClients.get(clientName);
64
+ }
65
+ }
48
66
  // options.default will be merge in to options.clients[id]
49
67
  config = (0, extend_1.extend)(true, {}, this.options['default'], config);
50
- const client = await this.createClient(config, clientName);
51
- if (client) {
68
+ const clientCreatingPromise = this.createClient(config, clientName);
69
+ if (clientCreatingPromise && types_1.Types.isPromise(clientCreatingPromise)) {
52
70
  if (clientName) {
53
- this.clients.set(clientName, client);
71
+ this.creatingClients.set(clientName, clientCreatingPromise);
54
72
  }
55
- return client;
73
+ return clientCreatingPromise
74
+ .then(client => {
75
+ if (clientName) {
76
+ this.clients.set(clientName, client);
77
+ }
78
+ return client;
79
+ })
80
+ .finally(() => {
81
+ if (clientName) {
82
+ this.creatingClients.delete(clientName);
83
+ }
84
+ });
85
+ }
86
+ // 处理同步返回的情况
87
+ if (clientName) {
88
+ this.clients.set(clientName, clientCreatingPromise);
56
89
  }
90
+ return clientCreatingPromise;
57
91
  }
58
92
  async destroyClient(client, clientName) { }
59
93
  async stop() {
60
94
  for (const [name, value] of this.clients.entries()) {
61
95
  await this.destroyClient(value, name);
62
96
  }
97
+ this.clients.clear();
63
98
  }
64
99
  getDefaultClientName() {
65
100
  return this.options['defaultClientName'];
@@ -6,6 +6,9 @@ exports.default = (appInfo) => {
6
6
  return {
7
7
  core: {
8
8
  healthCheckTimeout: 1000,
9
+ configLoadTimeout: 10000,
10
+ readyTimeout: 30000,
11
+ serverReadyTimeout: 30000,
9
12
  },
10
13
  asyncContextManager: {
11
14
  enable: true,
@@ -21,9 +21,9 @@ export declare class MidwayContainer implements IMidwayGlobalContainer {
21
21
  get identifierMapping(): IIdentifierRelationShip;
22
22
  addNamespace(ns: string): void;
23
23
  bindClass(exports: any, options?: Partial<IObjectDefinition>): void;
24
- bind<T>(target: T, options?: Partial<IObjectDefinition>): void;
25
- bind<T>(identifier: ObjectIdentifier, target: T, options?: Partial<IObjectDefinition>): void;
26
- protected bindModule(module: any, options: Partial<IObjectDefinition>): void;
24
+ bind<T>(target: T, options?: Partial<IObjectDefinition>): IObjectDefinition | undefined;
25
+ bind<T>(identifier: ObjectIdentifier, target: T, options?: Partial<IObjectDefinition>): IObjectDefinition | undefined;
26
+ protected bindModule(module: any, options: Partial<IObjectDefinition>): IObjectDefinition | undefined;
27
27
  setAttr(key: string, value: any): void;
28
28
  getAttr<T>(key: string): T;
29
29
  getIdentifier(identifier: ClassType | string): string;
@@ -37,6 +37,7 @@ export declare class MidwayContainer implements IMidwayGlobalContainer {
37
37
  * @param target
38
38
  */
39
39
  registerObject(identifier: ObjectIdentifier, target: any): void;
40
+ removeObject(identifier: ObjectIdentifier): void;
40
41
  onBeforeBind(fn: (Clzz: any, options: {
41
42
  context: IMidwayContainer;
42
43
  definition: IObjectDefinition;
@@ -162,13 +162,14 @@ class MidwayContainer {
162
162
  if (definition) {
163
163
  this.registry.registerDefinition(definition.id, definition);
164
164
  }
165
+ return definition;
165
166
  }
166
167
  bindModule(module, options) {
167
168
  if (types_1.Types.isClass(module)) {
168
169
  const providerId = decorator_1.DecoratorManager.getProviderUUId(module);
169
170
  if (providerId) {
170
171
  this.identifierMapping.saveClassRelation(module, options?.namespace);
171
- this.bind(providerId, module, options);
172
+ return this.bind(providerId, module, options);
172
173
  }
173
174
  else {
174
175
  // no provide or js class must be skip
@@ -182,7 +183,7 @@ class MidwayContainer {
182
183
  }
183
184
  const uuid = util_1.Utils.generateRandomId();
184
185
  this.identifierMapping.saveFunctionRelation(info.id, uuid);
185
- this.bind(uuid, module, {
186
+ return this.bind(uuid, module, {
186
187
  scope: info.scope,
187
188
  namespace: options.namespace,
188
189
  srcPath: options.srcPath,
@@ -231,6 +232,9 @@ class MidwayContainer {
231
232
  registerObject(identifier, target) {
232
233
  this.registry.registerObject(identifier, target);
233
234
  }
235
+ removeObject(identifier) {
236
+ this.registry.removeObject(identifier);
237
+ }
234
238
  onBeforeBind(fn) {
235
239
  this.objectCreateEventTarget.on(interface_1.ObjectLifeCycleEvent.BEFORE_BIND, fn);
236
240
  }
@@ -5,6 +5,7 @@ import { IIdentifierRelationShip, IObjectDefinition, IObjectDefinitionRegistry,
5
5
  export declare class ObjectDefinitionRegistry extends Map implements IObjectDefinitionRegistry {
6
6
  private singletonIds;
7
7
  private _identifierRelation;
8
+ private objectCache;
8
9
  get identifierRelation(): IIdentifierRelationShip;
9
10
  set identifierRelation(identifierRelation: IIdentifierRelationShip);
10
11
  get identifiers(): any[];
@@ -18,6 +19,7 @@ export declare class ObjectDefinitionRegistry extends Map implements IObjectDefi
18
19
  clearAll(): void;
19
20
  hasObject(identifier: ObjectIdentifier): boolean;
20
21
  registerObject(identifier: ObjectIdentifier, target: any): void;
22
+ removeObject(identifier: ObjectIdentifier): void;
21
23
  getObject(identifier: ObjectIdentifier): any;
22
24
  getIdentifierRelation(): IIdentifierRelationShip;
23
25
  setIdentifierRelation(identifierRelation: IIdentifierRelationShip): void;