@midwayjs/consul 3.20.5 → 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.
- package/dist/configuration.d.ts +2 -24
- package/dist/configuration.js +16 -66
- package/dist/extension/helper.d.ts +81 -0
- package/dist/extension/helper.js +143 -0
- package/dist/extension/serviceDiscovery.d.ts +45 -0
- package/dist/extension/serviceDiscovery.js +245 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/interface.d.ts +74 -67
- package/dist/manager.d.ts +19 -0
- package/dist/manager.js +74 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.js +45 -0
- package/index.d.ts +2 -2
- package/package.json +9 -9
- package/dist/config/config.default.d.ts +0 -19
- package/dist/config/config.default.js +0 -20
- package/dist/controller/consul.d.ts +0 -4
- package/dist/controller/consul.js +0 -31
- package/dist/lib/balancer.d.ts +0 -8
- package/dist/lib/balancer.js +0 -74
- package/dist/lib/provider.d.ts +0 -12
- package/dist/lib/provider.js +0 -22
- package/dist/service/balancer.d.ts +0 -9
- package/dist/service/balancer.js +0 -39
package/dist/configuration.d.ts
CHANGED
|
@@ -1,28 +1,6 @@
|
|
|
1
1
|
import { ILifeCycle, IMidwayApplication, IMidwayContainer } from '@midwayjs/core';
|
|
2
|
-
import { IConsulProviderInfoOptions, IConsulRegisterInfoOptions } from './interface';
|
|
3
|
-
import { ConsulProvider } from './lib/provider';
|
|
4
2
|
export declare class ConsulConfiguration implements ILifeCycle {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
8
|
-
consulProviderConfig: IConsulProviderInfoOptions;
|
|
9
|
-
/**
|
|
10
|
-
* 有关 service registry 注册的信息
|
|
11
|
-
*/
|
|
12
|
-
consulRegisterConfig: IConsulRegisterInfoOptions;
|
|
13
|
-
get consulProvider(): ConsulProvider;
|
|
14
|
-
/**
|
|
15
|
-
* 注册自己的条件
|
|
16
|
-
* 由于环境的复杂性(多网卡、自动端口冲突) address 和 port 必须提供
|
|
17
|
-
*/
|
|
18
|
-
get shouldBeRegisterMe(): boolean;
|
|
19
|
-
/**
|
|
20
|
-
* 注册 consul 服务
|
|
21
|
-
* @param container 容器 IoC
|
|
22
|
-
* @param app 应用 App
|
|
23
|
-
*/
|
|
24
|
-
registerConsul(container: IMidwayContainer, app: IMidwayApplication): Promise<void>;
|
|
25
|
-
onServerReady(container: IMidwayContainer, app?: IMidwayApplication): Promise<void>;
|
|
26
|
-
onStop(): Promise<void>;
|
|
3
|
+
onReady(container: IMidwayContainer, app?: IMidwayApplication): Promise<void>;
|
|
4
|
+
onStop(container: IMidwayContainer): Promise<void>;
|
|
27
5
|
}
|
|
28
6
|
//# sourceMappingURL=configuration.d.ts.map
|
package/dist/configuration.js
CHANGED
|
@@ -5,85 +5,35 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
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
6
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
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
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
9
|
exports.ConsulConfiguration = void 0;
|
|
13
10
|
const core_1 = require("@midwayjs/core");
|
|
14
|
-
const
|
|
15
|
-
const DefaultConfig = require("./config/config.default");
|
|
11
|
+
const manager_1 = require("./manager");
|
|
16
12
|
let ConsulConfiguration = class ConsulConfiguration {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
this[symbol] =
|
|
20
|
-
this[symbol] || new provider_1.ConsulProvider(this.consulProviderConfig);
|
|
21
|
-
return this[symbol];
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* 注册自己的条件
|
|
25
|
-
* 由于环境的复杂性(多网卡、自动端口冲突) address 和 port 必须提供
|
|
26
|
-
*/
|
|
27
|
-
get shouldBeRegisterMe() {
|
|
28
|
-
const { address, port } = this.consulRegisterConfig;
|
|
29
|
-
return this.consulProviderConfig.register && address.length > 0 && port > 0;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* 注册 consul 服务
|
|
33
|
-
* @param container 容器 IoC
|
|
34
|
-
* @param app 应用 App
|
|
35
|
-
*/
|
|
36
|
-
async registerConsul(container, app) {
|
|
37
|
-
const config = this.consulRegisterConfig;
|
|
38
|
-
const { address, port } = this.consulRegisterConfig;
|
|
39
|
-
// 把原始的 consul 对象注入到容器
|
|
40
|
-
container.registerObject('consul:consul', this.consulProvider.getConsul());
|
|
41
|
-
if (this.shouldBeRegisterMe) {
|
|
42
|
-
config.name = config.name || app.getProjectName();
|
|
43
|
-
config.id = config.id || `${config.name}:${address}:${port}`;
|
|
44
|
-
if (!config.check && config.check !== false) {
|
|
45
|
-
config.check = ['egg', 'koa', 'express'].includes(app.getNamespace())
|
|
46
|
-
? {
|
|
47
|
-
http: `http://${address}:${port}/consul/health/self/check`,
|
|
48
|
-
interval: '3s',
|
|
49
|
-
}
|
|
50
|
-
: {
|
|
51
|
-
tcp: `${address}:${port}`,
|
|
52
|
-
interval: '3s',
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
Object.assign(this.consulRegisterConfig, config);
|
|
56
|
-
await this.consulProvider.registerService(this.consulRegisterConfig);
|
|
57
|
-
}
|
|
13
|
+
async onReady(container, app) {
|
|
14
|
+
await container.getAsync(manager_1.ConsulServiceFactory);
|
|
58
15
|
}
|
|
59
|
-
async
|
|
60
|
-
await
|
|
61
|
-
|
|
62
|
-
async onStop() {
|
|
63
|
-
if (this.consulProviderConfig.register &&
|
|
64
|
-
this.consulProviderConfig.deregister) {
|
|
65
|
-
const { id } = this.consulRegisterConfig;
|
|
66
|
-
await this.consulProvider.deregisterService({ id });
|
|
67
|
-
}
|
|
16
|
+
async onStop(container) {
|
|
17
|
+
const factory = await container.getAsync(manager_1.ConsulServiceFactory);
|
|
18
|
+
await factory.stop();
|
|
68
19
|
}
|
|
69
20
|
};
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
__metadata("design:type", Object)
|
|
73
|
-
], ConsulConfiguration.prototype, "consulProviderConfig", void 0);
|
|
74
|
-
__decorate([
|
|
75
|
-
(0, core_1.Config)('consul.service'),
|
|
76
|
-
__metadata("design:type", Object)
|
|
77
|
-
], ConsulConfiguration.prototype, "consulRegisterConfig", void 0);
|
|
78
|
-
ConsulConfiguration = __decorate([
|
|
21
|
+
exports.ConsulConfiguration = ConsulConfiguration;
|
|
22
|
+
exports.ConsulConfiguration = ConsulConfiguration = __decorate([
|
|
79
23
|
(0, core_1.Configuration)({
|
|
80
24
|
namespace: 'consul',
|
|
81
25
|
importConfigs: [
|
|
82
26
|
{
|
|
83
|
-
default:
|
|
27
|
+
default: {
|
|
28
|
+
consul: {
|
|
29
|
+
serviceDiscovery: {
|
|
30
|
+
loadBalancer: 'roundRobin',
|
|
31
|
+
healthCheckType: 'self',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
84
35
|
},
|
|
85
36
|
],
|
|
86
37
|
})
|
|
87
38
|
], ConsulConfiguration);
|
|
88
|
-
exports.ConsulConfiguration = ConsulConfiguration;
|
|
89
39
|
//# sourceMappingURL=configuration.js.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { ILogger } from '@midwayjs/core';
|
|
2
|
+
/**
|
|
3
|
+
* Consul 服务实例 TTL 心跳上报工具类
|
|
4
|
+
*/
|
|
5
|
+
interface TTLHeartbeatOptions {
|
|
6
|
+
consul: any;
|
|
7
|
+
checkId: string;
|
|
8
|
+
interval?: number;
|
|
9
|
+
logger?: ILogger;
|
|
10
|
+
}
|
|
11
|
+
export declare class TTLHeartbeat {
|
|
12
|
+
private consul;
|
|
13
|
+
private checkId;
|
|
14
|
+
private interval;
|
|
15
|
+
private timer;
|
|
16
|
+
private logger;
|
|
17
|
+
/**
|
|
18
|
+
* @param {TTLHeartbeatOptions} options - 配置项
|
|
19
|
+
*/
|
|
20
|
+
constructor(options: TTLHeartbeatOptions);
|
|
21
|
+
/**
|
|
22
|
+
* 启动心跳
|
|
23
|
+
*/
|
|
24
|
+
start(): void;
|
|
25
|
+
/**
|
|
26
|
+
* 停止心跳
|
|
27
|
+
*/
|
|
28
|
+
stop(): void;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 计算 Consul 健康检查 TTL 毫秒值
|
|
32
|
+
* @param ttl 用户传入的 ttl,支持字符串(如 "30s"、"1m"、"1m30s")或数字(秒)
|
|
33
|
+
* @returns {number} 毫秒数,最小 1000ms
|
|
34
|
+
*/
|
|
35
|
+
export declare function calculateTTL(ttl: string): number;
|
|
36
|
+
/**
|
|
37
|
+
* HTTP 健康检查工具类
|
|
38
|
+
* 传入 http url,自动启动一个健康检查服务
|
|
39
|
+
*/
|
|
40
|
+
export declare class HTTPHealthCheck {
|
|
41
|
+
private server;
|
|
42
|
+
private port;
|
|
43
|
+
private path;
|
|
44
|
+
private message;
|
|
45
|
+
/**
|
|
46
|
+
* @param httpUrl 形如 'http://127.0.0.1:3000/health'
|
|
47
|
+
* @param message 健康时返回的内容,默认 'ok'
|
|
48
|
+
*/
|
|
49
|
+
constructor(httpUrl: string, message?: string);
|
|
50
|
+
/**
|
|
51
|
+
* 启动健康检查 HTTP 服务
|
|
52
|
+
*/
|
|
53
|
+
start(): void;
|
|
54
|
+
/**
|
|
55
|
+
* 停止健康检查 HTTP 服务
|
|
56
|
+
*/
|
|
57
|
+
stop(): void;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* TCP 健康检查工具类
|
|
61
|
+
* 传入 tcp url,自动启动一个 TCP 服务
|
|
62
|
+
*/
|
|
63
|
+
export declare class TCPHealthCheck {
|
|
64
|
+
private server;
|
|
65
|
+
private port;
|
|
66
|
+
private host;
|
|
67
|
+
/**
|
|
68
|
+
* @param tcpUrl 形如 'tcp://127.0.0.1:3000'
|
|
69
|
+
*/
|
|
70
|
+
constructor(tcpUrl: string);
|
|
71
|
+
/**
|
|
72
|
+
* 启动 TCP 健康检查服务
|
|
73
|
+
*/
|
|
74
|
+
start(): void;
|
|
75
|
+
/**
|
|
76
|
+
* 停止 TCP 健康检查服务
|
|
77
|
+
*/
|
|
78
|
+
stop(): void;
|
|
79
|
+
}
|
|
80
|
+
export {};
|
|
81
|
+
//# sourceMappingURL=helper.d.ts.map
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TCPHealthCheck = exports.HTTPHealthCheck = exports.calculateTTL = exports.TTLHeartbeat = void 0;
|
|
4
|
+
const ms_1 = require("ms");
|
|
5
|
+
const http_1 = require("http");
|
|
6
|
+
const url_1 = require("url");
|
|
7
|
+
const net_1 = require("net");
|
|
8
|
+
class TTLHeartbeat {
|
|
9
|
+
/**
|
|
10
|
+
* @param {TTLHeartbeatOptions} options - 配置项
|
|
11
|
+
*/
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.timer = null;
|
|
14
|
+
this.consul = options.consul;
|
|
15
|
+
this.checkId = options.checkId;
|
|
16
|
+
this.interval = options.interval ?? 5000;
|
|
17
|
+
this.logger = options.logger;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* 启动心跳
|
|
21
|
+
*/
|
|
22
|
+
start() {
|
|
23
|
+
if (this.timer)
|
|
24
|
+
return;
|
|
25
|
+
this.timer = setInterval(async () => {
|
|
26
|
+
try {
|
|
27
|
+
await this.consul.agent.check.pass(this.checkId);
|
|
28
|
+
// this.logger.info?.(`[TTL] ${this.checkId} 心跳上报成功`);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
this.logger.error(`[TTL] ${this.checkId} 心跳上报失败:`, err);
|
|
32
|
+
}
|
|
33
|
+
}, this.interval);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 停止心跳
|
|
37
|
+
*/
|
|
38
|
+
stop() {
|
|
39
|
+
if (this.timer) {
|
|
40
|
+
clearInterval(this.timer);
|
|
41
|
+
this.timer = null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.TTLHeartbeat = TTLHeartbeat;
|
|
46
|
+
/**
|
|
47
|
+
* 计算 Consul 健康检查 TTL 毫秒值
|
|
48
|
+
* @param ttl 用户传入的 ttl,支持字符串(如 "30s"、"1m"、"1m30s")或数字(秒)
|
|
49
|
+
* @returns {number} 毫秒数,最小 1000ms
|
|
50
|
+
*/
|
|
51
|
+
function calculateTTL(ttl) {
|
|
52
|
+
const ttlMs = (0, ms_1.default)(ttl);
|
|
53
|
+
// 最小不能低于 1 秒
|
|
54
|
+
return Math.max(ttlMs, 1000);
|
|
55
|
+
}
|
|
56
|
+
exports.calculateTTL = calculateTTL;
|
|
57
|
+
/**
|
|
58
|
+
* HTTP 健康检查工具类
|
|
59
|
+
* 传入 http url,自动启动一个健康检查服务
|
|
60
|
+
*/
|
|
61
|
+
class HTTPHealthCheck {
|
|
62
|
+
/**
|
|
63
|
+
* @param httpUrl 形如 'http://127.0.0.1:3000/health'
|
|
64
|
+
* @param message 健康时返回的内容,默认 'ok'
|
|
65
|
+
*/
|
|
66
|
+
constructor(httpUrl, message = 'ok') {
|
|
67
|
+
this.server = null;
|
|
68
|
+
const url = new url_1.URL(httpUrl);
|
|
69
|
+
this.port = Number(url.port) || 80;
|
|
70
|
+
this.path = url.pathname;
|
|
71
|
+
this.message = message;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 启动健康检查 HTTP 服务
|
|
75
|
+
*/
|
|
76
|
+
start() {
|
|
77
|
+
if (this.server)
|
|
78
|
+
return;
|
|
79
|
+
this.server = (0, http_1.createServer)((req, res) => {
|
|
80
|
+
if (req.url === this.path && req.method === 'GET') {
|
|
81
|
+
res.statusCode = 200;
|
|
82
|
+
res.end(this.message);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
res.statusCode = 404;
|
|
86
|
+
res.end('not found');
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
this.server.listen(this.port, () => {
|
|
90
|
+
console.log(`[health] 健康检查服务已启动: http://127.0.0.1:${this.port}${this.path}`);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 停止健康检查 HTTP 服务
|
|
95
|
+
*/
|
|
96
|
+
stop() {
|
|
97
|
+
if (this.server) {
|
|
98
|
+
this.server.close();
|
|
99
|
+
this.server = null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.HTTPHealthCheck = HTTPHealthCheck;
|
|
104
|
+
/**
|
|
105
|
+
* TCP 健康检查工具类
|
|
106
|
+
* 传入 tcp url,自动启动一个 TCP 服务
|
|
107
|
+
*/
|
|
108
|
+
class TCPHealthCheck {
|
|
109
|
+
/**
|
|
110
|
+
* @param tcpUrl 形如 'tcp://127.0.0.1:3000'
|
|
111
|
+
*/
|
|
112
|
+
constructor(tcpUrl) {
|
|
113
|
+
this.server = null;
|
|
114
|
+
const url = new url_1.URL(tcpUrl);
|
|
115
|
+
this.port = Number(url.port) || 80;
|
|
116
|
+
this.host = url.hostname || '0.0.0.0';
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 启动 TCP 健康检查服务
|
|
120
|
+
*/
|
|
121
|
+
start() {
|
|
122
|
+
if (this.server)
|
|
123
|
+
return;
|
|
124
|
+
this.server = (0, net_1.createServer)(socket => {
|
|
125
|
+
// 只要能建立连接就立即关闭
|
|
126
|
+
socket.end();
|
|
127
|
+
});
|
|
128
|
+
this.server.listen(this.port, this.host, () => {
|
|
129
|
+
console.log(`[tcp-health] TCP 健康检查服务已启动: tcp://${this.host}:${this.port}`);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 停止 TCP 健康检查服务
|
|
134
|
+
*/
|
|
135
|
+
stop() {
|
|
136
|
+
if (this.server) {
|
|
137
|
+
this.server.close();
|
|
138
|
+
this.server = null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
exports.TCPHealthCheck = TCPHealthCheck;
|
|
143
|
+
//# sourceMappingURL=helper.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ServiceDiscovery, ServiceDiscoveryClient, ILogger, MidwayWebRouterService, MidwayApplicationManager } from '@midwayjs/core';
|
|
2
|
+
import { ConsulServiceDiscoveryOptions, ConsulClient, ConsulInstanceMetadata, ConsulHealthItem, GetHealthServiceOptions } from '../interface';
|
|
3
|
+
/**
|
|
4
|
+
* The adapter for consul service discovery
|
|
5
|
+
* @since 4.0.0
|
|
6
|
+
*/
|
|
7
|
+
export declare class ConsulServiceDiscoverClient extends ServiceDiscoveryClient<ConsulClient, ConsulServiceDiscoveryOptions, ConsulInstanceMetadata, ConsulHealthItem> {
|
|
8
|
+
protected consul: ConsulClient;
|
|
9
|
+
protected readonly applicationManager: MidwayApplicationManager;
|
|
10
|
+
protected readonly webRouterService: MidwayWebRouterService;
|
|
11
|
+
protected readonly logger: ILogger;
|
|
12
|
+
private ttlHeartbeat?;
|
|
13
|
+
private httpHealthCheck?;
|
|
14
|
+
private tcpHealthCheck?;
|
|
15
|
+
constructor(consul: ConsulClient, serviceDiscoveryOptions: ConsulServiceDiscoveryOptions, applicationManager: MidwayApplicationManager, webRouterService: MidwayWebRouterService, logger: ILogger);
|
|
16
|
+
register(instance: ConsulInstanceMetadata): Promise<void>;
|
|
17
|
+
deregister(instance?: ConsulInstanceMetadata): Promise<void>;
|
|
18
|
+
private transformDefaultMetaToConsulInstance;
|
|
19
|
+
private updateStatus;
|
|
20
|
+
online(): Promise<void>;
|
|
21
|
+
offline(): Promise<void>;
|
|
22
|
+
beforeStop(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The service discovery for consul
|
|
26
|
+
* @since 4.0.0
|
|
27
|
+
*/
|
|
28
|
+
export declare class ConsulServiceDiscovery extends ServiceDiscovery<ConsulClient, ConsulServiceDiscoveryOptions, ConsulInstanceMetadata, ConsulHealthItem, GetHealthServiceOptions> {
|
|
29
|
+
private consulServiceFactory;
|
|
30
|
+
private consulServiceDiscoveryOptions;
|
|
31
|
+
private applicationManager;
|
|
32
|
+
private webRouterService;
|
|
33
|
+
private coreLogger;
|
|
34
|
+
private defaultServiceClient;
|
|
35
|
+
private listenerStore;
|
|
36
|
+
private configService;
|
|
37
|
+
init(): Promise<void>;
|
|
38
|
+
protected getServiceClient(): import("consul/lib/consul").Consul;
|
|
39
|
+
protected createServiceDiscoverClientImpl(options: ConsulServiceDiscoveryOptions): ConsulServiceDiscoverClient;
|
|
40
|
+
protected getDefaultServiceDiscoveryOptions(): ConsulServiceDiscoveryOptions;
|
|
41
|
+
private getListener;
|
|
42
|
+
getInstances(options: GetHealthServiceOptions): Promise<ConsulHealthItem[]>;
|
|
43
|
+
beforeStop(): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=serviceDiscovery.d.ts.map
|
|
@@ -0,0 +1,245 @@
|
|
|
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.ConsulServiceDiscovery = exports.ConsulServiceDiscoverClient = void 0;
|
|
13
|
+
const core_1 = require("@midwayjs/core");
|
|
14
|
+
const manager_1 = require("../manager");
|
|
15
|
+
const utils_1 = require("../utils");
|
|
16
|
+
const helper_1 = require("./helper");
|
|
17
|
+
/**
|
|
18
|
+
* The data listener for consul service discovery
|
|
19
|
+
* @since 4.0.0
|
|
20
|
+
*/
|
|
21
|
+
class ConsulDataListener extends core_1.DataListener {
|
|
22
|
+
constructor(client, options, logger) {
|
|
23
|
+
super();
|
|
24
|
+
this.client = client;
|
|
25
|
+
this.options = options;
|
|
26
|
+
this.logger = logger;
|
|
27
|
+
}
|
|
28
|
+
async init() {
|
|
29
|
+
await super.init();
|
|
30
|
+
}
|
|
31
|
+
// 初始化数据
|
|
32
|
+
async initData() {
|
|
33
|
+
const services = await this.client.health.service(this.options);
|
|
34
|
+
if (services && (0, utils_1.isObjectError)(services)) {
|
|
35
|
+
throw (0, utils_1.formatObjectErrorToError)(services);
|
|
36
|
+
}
|
|
37
|
+
return services;
|
|
38
|
+
}
|
|
39
|
+
// 更新数据
|
|
40
|
+
onData(setData) {
|
|
41
|
+
this.watcher = this.client.watch({
|
|
42
|
+
method: this.client.health.service,
|
|
43
|
+
options: this.options,
|
|
44
|
+
});
|
|
45
|
+
this.watcher.on('change', (healthItems, res) => {
|
|
46
|
+
setData(healthItems);
|
|
47
|
+
});
|
|
48
|
+
this.watcher.on('error', err => {
|
|
49
|
+
this.logger.error('[midway:consul] Error watching service:', err);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
async destroyListener() {
|
|
53
|
+
if (this.watcher) {
|
|
54
|
+
await this.watcher.end();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The adapter for consul service discovery
|
|
60
|
+
* @since 4.0.0
|
|
61
|
+
*/
|
|
62
|
+
class ConsulServiceDiscoverClient extends core_1.ServiceDiscoveryClient {
|
|
63
|
+
constructor(consul, serviceDiscoveryOptions, applicationManager, webRouterService, logger) {
|
|
64
|
+
super(consul, serviceDiscoveryOptions);
|
|
65
|
+
this.consul = consul;
|
|
66
|
+
this.applicationManager = applicationManager;
|
|
67
|
+
this.webRouterService = webRouterService;
|
|
68
|
+
this.logger = logger;
|
|
69
|
+
}
|
|
70
|
+
async register(instance) {
|
|
71
|
+
instance = this.transformDefaultMetaToConsulInstance(instance);
|
|
72
|
+
this.instance = instance;
|
|
73
|
+
if (!instance.name) {
|
|
74
|
+
throw new core_1.MidwayParameterError('instance.name is required when register service in consul');
|
|
75
|
+
}
|
|
76
|
+
const res = await this.client.agent.service.register(instance);
|
|
77
|
+
if (res && (0, utils_1.isObjectError)(res)) {
|
|
78
|
+
throw (0, utils_1.formatObjectErrorToError)(res);
|
|
79
|
+
}
|
|
80
|
+
this.logger.info(`[midway:consul] register instance: ${instance.id} for service: ${instance.name}`);
|
|
81
|
+
// set status to UP
|
|
82
|
+
await this.online();
|
|
83
|
+
this.logger.info(`[midway:consul] set status to UP for instance: ${instance.id} and service: ${instance.name}`);
|
|
84
|
+
if (this.options.autoHealthCheck) {
|
|
85
|
+
if (instance['check']?.['ttl']) {
|
|
86
|
+
this.ttlHeartbeat = new helper_1.TTLHeartbeat({
|
|
87
|
+
consul: this.client,
|
|
88
|
+
checkId: `service:${instance.id}`,
|
|
89
|
+
interval: (0, helper_1.calculateTTL)(instance['check']['ttl']),
|
|
90
|
+
});
|
|
91
|
+
this.ttlHeartbeat.start();
|
|
92
|
+
}
|
|
93
|
+
else if (instance['check']?.['http']) {
|
|
94
|
+
// 这里要判断下是否启动了 http 服务
|
|
95
|
+
const applications = this.applicationManager.getApplications([
|
|
96
|
+
'egg',
|
|
97
|
+
'koa',
|
|
98
|
+
'express',
|
|
99
|
+
]);
|
|
100
|
+
if (applications.length !== 0) {
|
|
101
|
+
const url = new URL(instance['check']['http']);
|
|
102
|
+
this.webRouterService.addRouter(async (_) => {
|
|
103
|
+
return 'success';
|
|
104
|
+
}, {
|
|
105
|
+
url: url.pathname,
|
|
106
|
+
requestMethod: 'GET',
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
this.httpHealthCheck = new helper_1.HTTPHealthCheck(instance['check']['http']);
|
|
111
|
+
this.httpHealthCheck.start();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else if (instance['check']?.['tcp']) {
|
|
115
|
+
this.tcpHealthCheck = new helper_1.TCPHealthCheck(instance['check']['tcp']);
|
|
116
|
+
this.tcpHealthCheck.start();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async deregister(instance) {
|
|
121
|
+
instance = instance ?? this.instance;
|
|
122
|
+
if (instance) {
|
|
123
|
+
const res = await this.client.agent.service.deregister(instance.id);
|
|
124
|
+
if (res && (0, utils_1.isObjectError)(res)) {
|
|
125
|
+
throw (0, utils_1.formatObjectErrorToError)(res);
|
|
126
|
+
}
|
|
127
|
+
this.logger.info(`[midway:consul] deregister instance: ${instance.id} for service: ${instance.name}`);
|
|
128
|
+
this.instance = undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
transformDefaultMetaToConsulInstance(instance) {
|
|
132
|
+
return {
|
|
133
|
+
name: instance?.serviceName,
|
|
134
|
+
address: instance?.host,
|
|
135
|
+
meta: instance?.metadata,
|
|
136
|
+
...instance,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
async updateStatus(instance, status) {
|
|
140
|
+
const checkId = `service:${instance.id}`;
|
|
141
|
+
if (status === 'UP') {
|
|
142
|
+
await this.client.agent.check.pass(checkId);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
await this.client.agent.check.fail(checkId);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async online() {
|
|
149
|
+
await this.updateStatus(this.instance, 'UP');
|
|
150
|
+
}
|
|
151
|
+
async offline() {
|
|
152
|
+
await this.updateStatus(this.instance, 'DOWN');
|
|
153
|
+
}
|
|
154
|
+
async beforeStop() {
|
|
155
|
+
await this.deregister();
|
|
156
|
+
if (this.ttlHeartbeat) {
|
|
157
|
+
this.ttlHeartbeat.stop();
|
|
158
|
+
}
|
|
159
|
+
if (this.httpHealthCheck) {
|
|
160
|
+
this.httpHealthCheck.stop();
|
|
161
|
+
}
|
|
162
|
+
if (this.tcpHealthCheck) {
|
|
163
|
+
this.tcpHealthCheck.stop();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
exports.ConsulServiceDiscoverClient = ConsulServiceDiscoverClient;
|
|
168
|
+
/**
|
|
169
|
+
* The service discovery for consul
|
|
170
|
+
* @since 4.0.0
|
|
171
|
+
*/
|
|
172
|
+
let ConsulServiceDiscovery = class ConsulServiceDiscovery extends core_1.ServiceDiscovery {
|
|
173
|
+
constructor() {
|
|
174
|
+
super(...arguments);
|
|
175
|
+
this.listenerStore = new Map();
|
|
176
|
+
}
|
|
177
|
+
async init() {
|
|
178
|
+
this.consulServiceDiscoveryOptions = this.configService.getConfiguration('consul.serviceDiscovery', {});
|
|
179
|
+
}
|
|
180
|
+
getServiceClient() {
|
|
181
|
+
if (!this.defaultServiceClient) {
|
|
182
|
+
this.defaultServiceClient = this.consulServiceFactory.get(this.consulServiceDiscoveryOptions.serviceDiscoveryClient ||
|
|
183
|
+
this.consulServiceFactory.getDefaultClientName() ||
|
|
184
|
+
'default');
|
|
185
|
+
}
|
|
186
|
+
return this.defaultServiceClient;
|
|
187
|
+
}
|
|
188
|
+
createServiceDiscoverClientImpl(options) {
|
|
189
|
+
return new ConsulServiceDiscoverClient(this.getServiceClient(), options, this.applicationManager, this.webRouterService, this.coreLogger);
|
|
190
|
+
}
|
|
191
|
+
getDefaultServiceDiscoveryOptions() {
|
|
192
|
+
return this.consulServiceDiscoveryOptions;
|
|
193
|
+
}
|
|
194
|
+
async getListener(options) {
|
|
195
|
+
const cacheKey = (0, utils_1.hashServiceOptions)(options);
|
|
196
|
+
if (!this.listenerStore.has(cacheKey)) {
|
|
197
|
+
const listener = new ConsulDataListener(this.getServiceClient(), options, this.coreLogger);
|
|
198
|
+
this.listenerStore.set(cacheKey, listener);
|
|
199
|
+
await listener.init();
|
|
200
|
+
}
|
|
201
|
+
return this.listenerStore.get(cacheKey);
|
|
202
|
+
}
|
|
203
|
+
async getInstances(options) {
|
|
204
|
+
const listener = await this.getListener({
|
|
205
|
+
passing: true,
|
|
206
|
+
...options,
|
|
207
|
+
});
|
|
208
|
+
return listener.getData();
|
|
209
|
+
}
|
|
210
|
+
async beforeStop() {
|
|
211
|
+
await Promise.all(Array.from(this.listenerStore.values()).map(listener => listener.destroyListener()));
|
|
212
|
+
this.listenerStore.clear();
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
exports.ConsulServiceDiscovery = ConsulServiceDiscovery;
|
|
216
|
+
__decorate([
|
|
217
|
+
(0, core_1.Inject)(),
|
|
218
|
+
__metadata("design:type", manager_1.ConsulServiceFactory)
|
|
219
|
+
], ConsulServiceDiscovery.prototype, "consulServiceFactory", void 0);
|
|
220
|
+
__decorate([
|
|
221
|
+
(0, core_1.Inject)(),
|
|
222
|
+
__metadata("design:type", core_1.MidwayApplicationManager)
|
|
223
|
+
], ConsulServiceDiscovery.prototype, "applicationManager", void 0);
|
|
224
|
+
__decorate([
|
|
225
|
+
(0, core_1.Inject)(),
|
|
226
|
+
__metadata("design:type", core_1.MidwayWebRouterService)
|
|
227
|
+
], ConsulServiceDiscovery.prototype, "webRouterService", void 0);
|
|
228
|
+
__decorate([
|
|
229
|
+
(0, core_1.Logger)(),
|
|
230
|
+
__metadata("design:type", Object)
|
|
231
|
+
], ConsulServiceDiscovery.prototype, "coreLogger", void 0);
|
|
232
|
+
__decorate([
|
|
233
|
+
(0, core_1.Inject)(),
|
|
234
|
+
__metadata("design:type", core_1.MidwayConfigService)
|
|
235
|
+
], ConsulServiceDiscovery.prototype, "configService", void 0);
|
|
236
|
+
__decorate([
|
|
237
|
+
(0, core_1.Init)(),
|
|
238
|
+
__metadata("design:type", Function),
|
|
239
|
+
__metadata("design:paramtypes", []),
|
|
240
|
+
__metadata("design:returntype", Promise)
|
|
241
|
+
], ConsulServiceDiscovery.prototype, "init", null);
|
|
242
|
+
exports.ConsulServiceDiscovery = ConsulServiceDiscovery = __decorate([
|
|
243
|
+
(0, core_1.Singleton)()
|
|
244
|
+
], ConsulServiceDiscovery);
|
|
245
|
+
//# sourceMappingURL=serviceDiscovery.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { ConsulConfiguration as Configuration } from './configuration';
|
|
2
|
-
export * from './controller/consul';
|
|
3
|
-
export * from './service/balancer';
|
|
4
2
|
export * from './interface';
|
|
3
|
+
export * from './extension/serviceDiscovery';
|
|
4
|
+
export * from './manager';
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
exports.Configuration = void 0;
|
|
18
18
|
var configuration_1 = require("./configuration");
|
|
19
19
|
Object.defineProperty(exports, "Configuration", { enumerable: true, get: function () { return configuration_1.ConsulConfiguration; } });
|
|
20
|
-
__exportStar(require("./controller/consul"), exports);
|
|
21
|
-
__exportStar(require("./service/balancer"), exports);
|
|
22
20
|
__exportStar(require("./interface"), exports);
|
|
21
|
+
__exportStar(require("./extension/serviceDiscovery"), exports);
|
|
22
|
+
__exportStar(require("./manager"), exports);
|
|
23
23
|
//# sourceMappingURL=index.js.map
|
package/dist/interface.d.ts
CHANGED
|
@@ -1,72 +1,79 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { ServiceDiscoveryOptions, DefaultInstanceMetadata } from '@midwayjs/core';
|
|
2
|
+
import Consul = require('consul');
|
|
3
|
+
export type ConsulOptions = ConstructorParameters<typeof Consul>[0];
|
|
4
|
+
export type ConsulClient = InstanceType<typeof Consul>;
|
|
5
|
+
type GetRegisterFn<T> = T extends {
|
|
6
|
+
register(options: any): any;
|
|
7
|
+
} ? T['register'] : never;
|
|
8
|
+
type GetFirstParam<T> = T extends {
|
|
9
|
+
(options: infer P, ...args: any[]): any;
|
|
10
|
+
(name: string): any;
|
|
11
|
+
} ? P : never;
|
|
12
|
+
export type RegisterOptions = GetFirstParam<GetRegisterFn<ConsulClient['agent']['service']>>;
|
|
13
|
+
/**
|
|
14
|
+
* From ConsulClient['health']['service']
|
|
15
|
+
*/
|
|
16
|
+
export type GetHealthServiceOptions = {
|
|
17
|
+
service: string;
|
|
18
|
+
dc?: string;
|
|
19
|
+
near?: string;
|
|
20
|
+
tag?: string;
|
|
21
|
+
passing?: boolean;
|
|
22
|
+
filter?: string;
|
|
23
|
+
peer?: string;
|
|
24
|
+
ns?: string;
|
|
25
|
+
};
|
|
26
|
+
export interface ConsulInstanceMetadata extends RegisterOptions {
|
|
11
27
|
}
|
|
12
|
-
export interface
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* @param strategy 负载均衡策略
|
|
16
|
-
*/
|
|
17
|
-
getServiceBalancer(strategy?: string): IServiceBalancer;
|
|
28
|
+
export interface ConsulServiceDiscoveryOptions extends ServiceDiscoveryOptions<ConsulHealthItem> {
|
|
29
|
+
serviceOptions?: ConsulInstanceMetadata | ((meta: DefaultInstanceMetadata) => ConsulInstanceMetadata);
|
|
30
|
+
autoHealthCheck?: boolean;
|
|
18
31
|
}
|
|
19
|
-
export interface
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* 调用服务负载均衡的策略(default、random),默认是 random 随机
|
|
31
|
-
*/
|
|
32
|
-
strategy?: string;
|
|
33
|
-
}
|
|
34
|
-
export interface IConsulRegisterInfoOptions extends RegisterOptions {
|
|
35
|
-
/**
|
|
36
|
-
* 注册 id 标识,默认是 name:address:port 的组合
|
|
37
|
-
*/
|
|
38
|
-
id?: string;
|
|
39
|
-
/**
|
|
40
|
-
* 服务名称
|
|
41
|
-
*/
|
|
42
|
-
name: string;
|
|
43
|
-
/**
|
|
44
|
-
* 服务地址
|
|
45
|
-
*/
|
|
46
|
-
address: string;
|
|
47
|
-
/**
|
|
48
|
-
* 服务端口
|
|
49
|
-
*/
|
|
50
|
-
port: number;
|
|
51
|
-
/**
|
|
52
|
-
* 服务标签
|
|
53
|
-
*/
|
|
54
|
-
tags?: string[];
|
|
55
|
-
/**
|
|
56
|
-
* 健康检查配置,组件默认会配置一个(检查间隔是3秒),如果指定 check=false 则关闭 consul 健康检查
|
|
57
|
-
*/
|
|
58
|
-
check?: {
|
|
59
|
-
tcp?: string;
|
|
60
|
-
http?: string;
|
|
61
|
-
script?: string;
|
|
62
|
-
interval?: string;
|
|
63
|
-
ttl?: string;
|
|
64
|
-
notes?: string;
|
|
65
|
-
status?: string;
|
|
32
|
+
export interface ConsulHealthItem {
|
|
33
|
+
Node: {
|
|
34
|
+
ID: string;
|
|
35
|
+
Node: string;
|
|
36
|
+
Address: string;
|
|
37
|
+
Datacenter: string;
|
|
38
|
+
TaggedAddresses: Record<string, any>;
|
|
39
|
+
Meta: Record<string, any>;
|
|
40
|
+
CreateIndex: number;
|
|
41
|
+
ModifyIndex: number;
|
|
66
42
|
};
|
|
43
|
+
Service: {
|
|
44
|
+
ID: string;
|
|
45
|
+
Service: string;
|
|
46
|
+
Tags: string[];
|
|
47
|
+
Address: string;
|
|
48
|
+
TaggedAddresses: Record<string, any>;
|
|
49
|
+
Meta: Record<string, any>;
|
|
50
|
+
Port: number;
|
|
51
|
+
Weights: Record<string, any>;
|
|
52
|
+
EnableTagOverride: boolean;
|
|
53
|
+
Proxy: Record<string, any>;
|
|
54
|
+
Connect: Record<string, any>;
|
|
55
|
+
PeerName: string;
|
|
56
|
+
CreateIndex: number;
|
|
57
|
+
ModifyIndex: number;
|
|
58
|
+
};
|
|
59
|
+
Checks: Array<{
|
|
60
|
+
Node: string;
|
|
61
|
+
CheckID: string;
|
|
62
|
+
Name: string;
|
|
63
|
+
Status: 'passing' | 'warning' | 'critical';
|
|
64
|
+
Notes: string;
|
|
65
|
+
Output: string;
|
|
66
|
+
ServiceID: string;
|
|
67
|
+
ServiceName: string;
|
|
68
|
+
ServiceTags: string[];
|
|
69
|
+
Type: string;
|
|
70
|
+
Interval: string;
|
|
71
|
+
Timeout: string;
|
|
72
|
+
ExposedPort: number;
|
|
73
|
+
Definition: Record<string, any>;
|
|
74
|
+
CreateIndex: number;
|
|
75
|
+
ModifyIndex: number;
|
|
76
|
+
}>;
|
|
67
77
|
}
|
|
68
|
-
export
|
|
69
|
-
provider?: IConsulProviderInfoOptions;
|
|
70
|
-
service?: IConsulRegisterInfoOptions;
|
|
71
|
-
}
|
|
78
|
+
export {};
|
|
72
79
|
//# sourceMappingURL=interface.d.ts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ServiceFactory, ServiceFactoryConfigOption, ILogger } from '@midwayjs/core';
|
|
2
|
+
import Consul = require('consul');
|
|
3
|
+
import { ConsulClient, ConsulOptions } from './interface';
|
|
4
|
+
export declare class ConsulServiceFactory extends ServiceFactory<ConsulClient> {
|
|
5
|
+
consulConfig: ServiceFactoryConfigOption<ConsulOptions>;
|
|
6
|
+
init(): Promise<void>;
|
|
7
|
+
logger: ILogger;
|
|
8
|
+
createClient(config: ConsulOptions, clientName: string): Promise<InstanceType<typeof Consul>>;
|
|
9
|
+
getName(): string;
|
|
10
|
+
destroyClient(client: InstanceType<typeof Consul>, clientName: string): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export declare class ConsulService implements InstanceType<typeof Consul> {
|
|
13
|
+
private serviceFactory;
|
|
14
|
+
private instance;
|
|
15
|
+
init(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export interface ConsulService extends InstanceType<typeof Consul> {
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=manager.d.ts.map
|
package/dist/manager.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
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.ConsulService = exports.ConsulServiceFactory = void 0;
|
|
13
|
+
const core_1 = require("@midwayjs/core");
|
|
14
|
+
const Consul = require("consul");
|
|
15
|
+
let ConsulServiceFactory = class ConsulServiceFactory extends core_1.ServiceFactory {
|
|
16
|
+
async init() {
|
|
17
|
+
await this.initClients(this.consulConfig, {
|
|
18
|
+
concurrent: true,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async createClient(config, clientName) {
|
|
22
|
+
this.logger.info('[midway:consul] init %s at %s:%s', clientName, config.host, config.port);
|
|
23
|
+
return new Consul(config);
|
|
24
|
+
}
|
|
25
|
+
getName() {
|
|
26
|
+
return 'consul';
|
|
27
|
+
}
|
|
28
|
+
async destroyClient(client, clientName) {
|
|
29
|
+
this.logger.info('[midway:consul] destroy %s', clientName);
|
|
30
|
+
client.destroy();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
exports.ConsulServiceFactory = ConsulServiceFactory;
|
|
34
|
+
__decorate([
|
|
35
|
+
(0, core_1.Config)('consul'),
|
|
36
|
+
__metadata("design:type", Object)
|
|
37
|
+
], ConsulServiceFactory.prototype, "consulConfig", void 0);
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, core_1.Init)(),
|
|
40
|
+
__metadata("design:type", Function),
|
|
41
|
+
__metadata("design:paramtypes", []),
|
|
42
|
+
__metadata("design:returntype", Promise)
|
|
43
|
+
], ConsulServiceFactory.prototype, "init", null);
|
|
44
|
+
__decorate([
|
|
45
|
+
(0, core_1.Logger)('coreLogger'),
|
|
46
|
+
__metadata("design:type", Object)
|
|
47
|
+
], ConsulServiceFactory.prototype, "logger", void 0);
|
|
48
|
+
exports.ConsulServiceFactory = ConsulServiceFactory = __decorate([
|
|
49
|
+
(0, core_1.Singleton)()
|
|
50
|
+
], ConsulServiceFactory);
|
|
51
|
+
let ConsulService = class ConsulService {
|
|
52
|
+
async init() {
|
|
53
|
+
this.instance = this.serviceFactory.get(this.serviceFactory.getDefaultClientName?.() || 'default');
|
|
54
|
+
if (!this.instance) {
|
|
55
|
+
throw new core_1.MidwayCommonError('consul default instance not found.');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
exports.ConsulService = ConsulService;
|
|
60
|
+
__decorate([
|
|
61
|
+
(0, core_1.Inject)(),
|
|
62
|
+
__metadata("design:type", ConsulServiceFactory)
|
|
63
|
+
], ConsulService.prototype, "serviceFactory", void 0);
|
|
64
|
+
__decorate([
|
|
65
|
+
(0, core_1.Init)(),
|
|
66
|
+
__metadata("design:type", Function),
|
|
67
|
+
__metadata("design:paramtypes", []),
|
|
68
|
+
__metadata("design:returntype", Promise)
|
|
69
|
+
], ConsulService.prototype, "init", null);
|
|
70
|
+
exports.ConsulService = ConsulService = __decorate([
|
|
71
|
+
(0, core_1.Singleton)()
|
|
72
|
+
], ConsulService);
|
|
73
|
+
(0, core_1.delegateTargetAllPrototypeMethod)(ConsulService, Consul);
|
|
74
|
+
//# sourceMappingURL=manager.js.map
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { MidwayCommonError } from '@midwayjs/core';
|
|
2
|
+
import { GetHealthServiceOptions } from './interface';
|
|
3
|
+
export declare function isObjectError(obj: any): boolean;
|
|
4
|
+
export declare function formatObjectErrorToError(obj: any): MidwayCommonError;
|
|
5
|
+
/**
|
|
6
|
+
* 对于 1 万个不同 ServiceOptions 组合,使用当前这个基于 DJB2 + base36 的方法,冲突概率大约是 0.1%,也就是理论上每 1 万个中只有 10 个左右可能冲突,而且这还是在完全随机分布的情况下估算的
|
|
7
|
+
* 适用于对象类型是扁平的,没有嵌套
|
|
8
|
+
*
|
|
9
|
+
* @param options
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
export declare function hashServiceOptions(options: GetHealthServiceOptions): string;
|
|
13
|
+
//# sourceMappingURL=utils.d.ts.map
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hashServiceOptions = exports.formatObjectErrorToError = exports.isObjectError = void 0;
|
|
4
|
+
const core_1 = require("@midwayjs/core");
|
|
5
|
+
function isObjectError(obj) {
|
|
6
|
+
return obj && typeof obj === 'object' && 'errno' in obj;
|
|
7
|
+
}
|
|
8
|
+
exports.isObjectError = isObjectError;
|
|
9
|
+
function formatObjectErrorToError(obj) {
|
|
10
|
+
const err = new Error(obj.message);
|
|
11
|
+
err.stack = obj.stack;
|
|
12
|
+
err.errno = obj.errno;
|
|
13
|
+
for (const key in obj) {
|
|
14
|
+
if (key !== 'errno' && key !== 'stack') {
|
|
15
|
+
err[key] = obj[key];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const commonErr = new core_1.MidwayCommonError(obj.message);
|
|
19
|
+
err.cause = commonErr;
|
|
20
|
+
return commonErr;
|
|
21
|
+
}
|
|
22
|
+
exports.formatObjectErrorToError = formatObjectErrorToError;
|
|
23
|
+
/**
|
|
24
|
+
* 对于 1 万个不同 ServiceOptions 组合,使用当前这个基于 DJB2 + base36 的方法,冲突概率大约是 0.1%,也就是理论上每 1 万个中只有 10 个左右可能冲突,而且这还是在完全随机分布的情况下估算的
|
|
25
|
+
* 适用于对象类型是扁平的,没有嵌套
|
|
26
|
+
*
|
|
27
|
+
* @param options
|
|
28
|
+
* @returns
|
|
29
|
+
*/
|
|
30
|
+
function hashServiceOptions(options) {
|
|
31
|
+
const keys = Object.keys(options).sort();
|
|
32
|
+
let str = '';
|
|
33
|
+
for (const key of keys) {
|
|
34
|
+
const value = options[key];
|
|
35
|
+
str += `${key}:${String(value)}|`;
|
|
36
|
+
}
|
|
37
|
+
// 简单快速 hash 算法(DJB2 改进)
|
|
38
|
+
let hash = 5381;
|
|
39
|
+
for (let i = 0; i < str.length; i++) {
|
|
40
|
+
hash = (hash * 33) ^ str.charCodeAt(i);
|
|
41
|
+
}
|
|
42
|
+
return (hash >>> 0).toString(36); // 无符号,base36 更短
|
|
43
|
+
}
|
|
44
|
+
exports.hashServiceOptions = hashServiceOptions;
|
|
45
|
+
//# sourceMappingURL=utils.js.map
|
package/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ConsulOptions } from './dist';
|
|
2
2
|
|
|
3
3
|
export * from './dist/index';
|
|
4
4
|
|
|
5
5
|
declare module '@midwayjs/core/dist/interface' {
|
|
6
6
|
interface MidwayConfig {
|
|
7
|
-
consul?:
|
|
7
|
+
consul?: ServiceFactoryConfigOption<ConsulOptions>;
|
|
8
8
|
}
|
|
9
9
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midwayjs/consul",
|
|
3
3
|
"description": "midway consul",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.0-beta.1",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -10,15 +10,15 @@
|
|
|
10
10
|
"index.d.ts"
|
|
11
11
|
],
|
|
12
12
|
"devDependencies": {
|
|
13
|
-
"@midwayjs/core": "^
|
|
14
|
-
"@midwayjs/koa": "^
|
|
15
|
-
"@midwayjs/mock": "^
|
|
16
|
-
"@types/consul": "0.40.3",
|
|
13
|
+
"@midwayjs/core": "^4.0.0-beta.1",
|
|
14
|
+
"@midwayjs/koa": "^4.0.0-beta.1",
|
|
15
|
+
"@midwayjs/mock": "^4.0.0-beta.1",
|
|
17
16
|
"@types/sinon": "17.0.3",
|
|
18
17
|
"nock": "13.5.6"
|
|
19
18
|
},
|
|
20
19
|
"dependencies": {
|
|
21
|
-
"consul": "
|
|
20
|
+
"consul": "2.0.1",
|
|
21
|
+
"ms": "2.1.3"
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|
|
24
24
|
"consul"
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"scripts": {
|
|
29
29
|
"build": "tsc",
|
|
30
|
-
"test": "node
|
|
31
|
-
"cov": "node
|
|
30
|
+
"test": "node -r ts-node/register ../../node_modules/jest/bin/jest.js --runInBand",
|
|
31
|
+
"cov": "node -r ts-node/register ../../node_modules/jest/bin/jest.js --runInBand --coverage --forceExit",
|
|
32
32
|
"ci": "npm run test",
|
|
33
33
|
"lint": "mwts check"
|
|
34
34
|
},
|
|
@@ -39,5 +39,5 @@
|
|
|
39
39
|
"type": "git",
|
|
40
40
|
"url": "https://github.com/midwayjs/midway.git"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "832961ec3aff123c033197d8c00cb2bc9bad7ff8"
|
|
43
43
|
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
declare const _default: {
|
|
2
|
-
consul: {
|
|
3
|
-
provider: {
|
|
4
|
-
register: boolean;
|
|
5
|
-
host: string;
|
|
6
|
-
port: number;
|
|
7
|
-
strategy: string;
|
|
8
|
-
};
|
|
9
|
-
service: {
|
|
10
|
-
id: any;
|
|
11
|
-
name: any;
|
|
12
|
-
tags: any[];
|
|
13
|
-
address: any;
|
|
14
|
-
port: number;
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
export default _default;
|
|
19
|
-
//# sourceMappingURL=config.default.d.ts.map
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.default = {
|
|
4
|
-
consul: {
|
|
5
|
-
provider: {
|
|
6
|
-
register: false,
|
|
7
|
-
host: '127.0.0.1',
|
|
8
|
-
port: 8500,
|
|
9
|
-
strategy: 'random',
|
|
10
|
-
},
|
|
11
|
-
service: {
|
|
12
|
-
id: null,
|
|
13
|
-
name: null,
|
|
14
|
-
tags: [],
|
|
15
|
-
address: null,
|
|
16
|
-
port: 7001,
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
};
|
|
20
|
-
//# sourceMappingURL=config.default.js.map
|
|
@@ -1,31 +0,0 @@
|
|
|
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.ConsulController = void 0;
|
|
13
|
-
const core_1 = require("@midwayjs/core");
|
|
14
|
-
let ConsulController = class ConsulController {
|
|
15
|
-
async healthCheck() {
|
|
16
|
-
return {
|
|
17
|
-
status: 'success',
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
__decorate([
|
|
22
|
-
(0, core_1.Get)('/health/self/check'),
|
|
23
|
-
__metadata("design:type", Function),
|
|
24
|
-
__metadata("design:paramtypes", []),
|
|
25
|
-
__metadata("design:returntype", Promise)
|
|
26
|
-
], ConsulController.prototype, "healthCheck", null);
|
|
27
|
-
ConsulController = __decorate([
|
|
28
|
-
(0, core_1.Controller)('/consul')
|
|
29
|
-
], ConsulController);
|
|
30
|
-
exports.ConsulController = ConsulController;
|
|
31
|
-
//# sourceMappingURL=consul.js.map
|
package/dist/lib/balancer.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import * as Consul from 'consul';
|
|
2
|
-
import { IServiceBalancer, IConsulBalancer } from '../interface';
|
|
3
|
-
export declare class ConsulBalancer implements IConsulBalancer {
|
|
4
|
-
private consul;
|
|
5
|
-
constructor(consul: Consul.Consul);
|
|
6
|
-
getServiceBalancer(strategy?: string): IServiceBalancer;
|
|
7
|
-
}
|
|
8
|
-
//# sourceMappingURL=balancer.d.ts.map
|
package/dist/lib/balancer.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ConsulBalancer = void 0;
|
|
4
|
-
class Balancer {
|
|
5
|
-
constructor(consul) {
|
|
6
|
-
this.consul = consul;
|
|
7
|
-
//
|
|
8
|
-
}
|
|
9
|
-
async select(serviceName, passingOnly = true) {
|
|
10
|
-
// throw new Error('not implemented');
|
|
11
|
-
}
|
|
12
|
-
async loadServices(serviceName, passingOnly = true) {
|
|
13
|
-
if (passingOnly)
|
|
14
|
-
return await this.loadPassing(serviceName);
|
|
15
|
-
return await this.loadAll(serviceName);
|
|
16
|
-
}
|
|
17
|
-
async loadAll(serviceName) {
|
|
18
|
-
return (await this.consul.catalog.service.nodes(serviceName));
|
|
19
|
-
}
|
|
20
|
-
async loadPassing(serviceName) {
|
|
21
|
-
const passingIds = [];
|
|
22
|
-
const checks = (await this.consul.health.checks(serviceName));
|
|
23
|
-
// 健康检查通过的
|
|
24
|
-
checks.forEach(check => {
|
|
25
|
-
if (check.Status === 'passing') {
|
|
26
|
-
passingIds.push(check.ServiceID);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
const instances = await this.loadAll(serviceName);
|
|
30
|
-
return instances.filter(item => passingIds.includes(item.ServiceID));
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
class RandomBalancer extends Balancer {
|
|
34
|
-
constructor(consul) {
|
|
35
|
-
super(consul);
|
|
36
|
-
}
|
|
37
|
-
async select(serviceName, passingOnly = true) {
|
|
38
|
-
let instances = await this.loadServices(serviceName, passingOnly);
|
|
39
|
-
if (instances.length > 0) {
|
|
40
|
-
instances = this.shuffle(instances);
|
|
41
|
-
return instances[Math.floor(Math.random() * instances.length)];
|
|
42
|
-
}
|
|
43
|
-
throw new Error('no available instance named ' + serviceName);
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* shuff by fisher-yates
|
|
47
|
-
*/
|
|
48
|
-
shuffle(instances) {
|
|
49
|
-
const result = [];
|
|
50
|
-
for (let i = 0; i < instances.length; i++) {
|
|
51
|
-
const j = Math.floor(Math.random() * (i + 1));
|
|
52
|
-
if (j !== i) {
|
|
53
|
-
result[i] = result[j];
|
|
54
|
-
}
|
|
55
|
-
result[j] = instances[i];
|
|
56
|
-
}
|
|
57
|
-
return result;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
class ConsulBalancer {
|
|
61
|
-
constructor(consul) {
|
|
62
|
-
this.consul = consul;
|
|
63
|
-
//
|
|
64
|
-
}
|
|
65
|
-
getServiceBalancer(strategy) {
|
|
66
|
-
switch (strategy) {
|
|
67
|
-
case 'random':
|
|
68
|
-
return new RandomBalancer(this.consul);
|
|
69
|
-
}
|
|
70
|
-
throw new Error('invalid strategy balancer');
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
exports.ConsulBalancer = ConsulBalancer;
|
|
74
|
-
//# sourceMappingURL=balancer.js.map
|
package/dist/lib/provider.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { IConsulProviderInfoOptions, IConsulRegisterInfoOptions } from '../interface';
|
|
2
|
-
import * as Consul from 'consul';
|
|
3
|
-
export declare class ConsulProvider {
|
|
4
|
-
private readonly consul;
|
|
5
|
-
constructor(providerOptions: IConsulProviderInfoOptions);
|
|
6
|
-
getConsul(): Consul.Consul;
|
|
7
|
-
registerService(registerOptions: IConsulRegisterInfoOptions): Promise<void>;
|
|
8
|
-
deregisterService(deregisterOptions: {
|
|
9
|
-
id: string;
|
|
10
|
-
}): Promise<void>;
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=provider.d.ts.map
|
package/dist/lib/provider.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ConsulProvider = void 0;
|
|
4
|
-
const Consul = require("consul");
|
|
5
|
-
class ConsulProvider {
|
|
6
|
-
constructor(providerOptions) {
|
|
7
|
-
// should be, ignore config
|
|
8
|
-
providerOptions.promisify = true;
|
|
9
|
-
this.consul = new Consul(providerOptions);
|
|
10
|
-
}
|
|
11
|
-
getConsul() {
|
|
12
|
-
return this.consul;
|
|
13
|
-
}
|
|
14
|
-
async registerService(registerOptions) {
|
|
15
|
-
await this.consul.agent.service.register(registerOptions);
|
|
16
|
-
}
|
|
17
|
-
async deregisterService(deregisterOptions) {
|
|
18
|
-
await this.consul.agent.service.deregister(deregisterOptions);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
exports.ConsulProvider = ConsulProvider;
|
|
22
|
-
//# sourceMappingURL=provider.js.map
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import * as Consul from 'consul';
|
|
2
|
-
import { IServiceBalancer, IConsulBalancer } from '../interface';
|
|
3
|
-
export declare class BalancerService implements IConsulBalancer {
|
|
4
|
-
consul: Consul.Consul;
|
|
5
|
-
private consulBalancer;
|
|
6
|
-
init(): void;
|
|
7
|
-
getServiceBalancer(strategy?: string): IServiceBalancer;
|
|
8
|
-
}
|
|
9
|
-
//# sourceMappingURL=balancer.d.ts.map
|
package/dist/service/balancer.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
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.BalancerService = void 0;
|
|
13
|
-
const core_1 = require("@midwayjs/core");
|
|
14
|
-
const balancer_1 = require("../lib/balancer");
|
|
15
|
-
const Consul = require("consul");
|
|
16
|
-
let BalancerService = class BalancerService {
|
|
17
|
-
init() {
|
|
18
|
-
this.consulBalancer = new balancer_1.ConsulBalancer(this.consul);
|
|
19
|
-
}
|
|
20
|
-
getServiceBalancer(strategy = 'random') {
|
|
21
|
-
return this.consulBalancer.getServiceBalancer(strategy);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
__decorate([
|
|
25
|
-
(0, core_1.Inject)('consul:consul'),
|
|
26
|
-
__metadata("design:type", Object)
|
|
27
|
-
], BalancerService.prototype, "consul", void 0);
|
|
28
|
-
__decorate([
|
|
29
|
-
(0, core_1.Init)(),
|
|
30
|
-
__metadata("design:type", Function),
|
|
31
|
-
__metadata("design:paramtypes", []),
|
|
32
|
-
__metadata("design:returntype", void 0)
|
|
33
|
-
], BalancerService.prototype, "init", null);
|
|
34
|
-
BalancerService = __decorate([
|
|
35
|
-
(0, core_1.Provide)(),
|
|
36
|
-
(0, core_1.Scope)(core_1.ScopeEnum.Singleton)
|
|
37
|
-
], BalancerService);
|
|
38
|
-
exports.BalancerService = BalancerService;
|
|
39
|
-
//# sourceMappingURL=balancer.js.map
|