@hazeljs/discovery 0.2.0-beta.16 → 0.2.0-beta.17
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 +185 -19
- package/dist/__tests__/consul-backend.test.d.ts +6 -0
- package/dist/__tests__/consul-backend.test.d.ts.map +1 -0
- package/dist/__tests__/consul-backend.test.js +300 -0
- package/dist/__tests__/kubernetes-backend.test.d.ts +6 -0
- package/dist/__tests__/kubernetes-backend.test.d.ts.map +1 -0
- package/dist/__tests__/kubernetes-backend.test.js +261 -0
- package/dist/__tests__/redis-backend.test.d.ts +6 -0
- package/dist/__tests__/redis-backend.test.d.ts.map +1 -0
- package/dist/__tests__/redis-backend.test.js +280 -0
- package/dist/backends/consul-backend.d.ts +46 -7
- package/dist/backends/consul-backend.d.ts.map +1 -1
- package/dist/backends/consul-backend.js +23 -39
- package/dist/backends/kubernetes-backend.d.ts +44 -6
- package/dist/backends/kubernetes-backend.d.ts.map +1 -1
- package/dist/backends/kubernetes-backend.js +11 -32
- package/dist/backends/memory-backend.d.ts +0 -1
- package/dist/backends/memory-backend.d.ts.map +1 -1
- package/dist/backends/memory-backend.js +3 -32
- package/dist/backends/redis-backend.d.ts +11 -6
- package/dist/backends/redis-backend.d.ts.map +1 -1
- package/dist/backends/redis-backend.js +66 -46
- package/dist/client/discovery-client.d.ts +6 -4
- package/dist/client/discovery-client.d.ts.map +1 -1
- package/dist/client/discovery-client.js +30 -30
- package/dist/client/service-client.d.ts.map +1 -1
- package/dist/client/service-client.js +82 -17
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/registry/service-registry.d.ts.map +1 -1
- package/dist/registry/service-registry.js +13 -2
- package/dist/utils/filter.d.ts +10 -0
- package/dist/utils/filter.d.ts.map +1 -0
- package/dist/utils/filter.js +39 -0
- package/dist/utils/logger.d.ts +21 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +34 -0
- package/dist/utils/validation.d.ts +36 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +109 -0
- package/package.json +3 -3
|
@@ -6,9 +6,13 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.ConsulRegistryBackend = void 0;
|
|
8
8
|
const types_1 = require("../types");
|
|
9
|
+
const filter_1 = require("../utils/filter");
|
|
10
|
+
const logger_1 = require("../utils/logger");
|
|
11
|
+
const validation_1 = require("../utils/validation");
|
|
9
12
|
class ConsulRegistryBackend {
|
|
10
13
|
constructor(consul, config = {}) {
|
|
11
14
|
this.checkIntervals = new Map();
|
|
15
|
+
(0, validation_1.validateConsulBackendConfig)(config);
|
|
12
16
|
this.consul = consul;
|
|
13
17
|
this.ttl = config.ttl || '30s';
|
|
14
18
|
}
|
|
@@ -51,19 +55,21 @@ class ConsulRegistryBackend {
|
|
|
51
55
|
* Update service instance heartbeat
|
|
52
56
|
*/
|
|
53
57
|
async heartbeat(instanceId) {
|
|
58
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
54
59
|
const checkId = `service:${instanceId}`;
|
|
55
60
|
try {
|
|
56
61
|
// Pass TTL check
|
|
57
62
|
await this.consul.agent.check.pass(checkId);
|
|
58
63
|
}
|
|
59
|
-
catch {
|
|
60
|
-
|
|
64
|
+
catch (error) {
|
|
65
|
+
logger.warn(`Consul heartbeat failed for ${instanceId}, will retry on next heartbeat`, error);
|
|
61
66
|
}
|
|
62
67
|
}
|
|
63
68
|
/**
|
|
64
69
|
* Get all instances of a service
|
|
65
70
|
*/
|
|
66
71
|
async getInstances(serviceName, filter) {
|
|
72
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
67
73
|
try {
|
|
68
74
|
const result = await this.consul.health.service({
|
|
69
75
|
service: serviceName,
|
|
@@ -99,12 +105,10 @@ class ConsulRegistryBackend {
|
|
|
99
105
|
};
|
|
100
106
|
});
|
|
101
107
|
// Apply additional filters
|
|
102
|
-
|
|
103
|
-
return this.applyFilter(instances, filter);
|
|
104
|
-
}
|
|
105
|
-
return instances;
|
|
108
|
+
return (0, filter_1.applyServiceFilter)(instances, filter);
|
|
106
109
|
}
|
|
107
|
-
catch {
|
|
110
|
+
catch (error) {
|
|
111
|
+
logger.error(`Failed to get instances for service "${serviceName}" from Consul`, error);
|
|
108
112
|
return [];
|
|
109
113
|
}
|
|
110
114
|
}
|
|
@@ -112,6 +116,7 @@ class ConsulRegistryBackend {
|
|
|
112
116
|
* Get a specific service instance
|
|
113
117
|
*/
|
|
114
118
|
async getInstance(instanceId) {
|
|
119
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
115
120
|
try {
|
|
116
121
|
const services = await this.consul.agent.service.list();
|
|
117
122
|
const service = services[instanceId];
|
|
@@ -144,7 +149,8 @@ class ConsulRegistryBackend {
|
|
|
144
149
|
registeredAt: service.Meta?.registeredAt ? new Date(service.Meta.registeredAt) : new Date(),
|
|
145
150
|
};
|
|
146
151
|
}
|
|
147
|
-
catch {
|
|
152
|
+
catch (error) {
|
|
153
|
+
logger.error(`Failed to get instance "${instanceId}" from Consul`, error);
|
|
148
154
|
return null;
|
|
149
155
|
}
|
|
150
156
|
}
|
|
@@ -152,11 +158,13 @@ class ConsulRegistryBackend {
|
|
|
152
158
|
* Get all registered services
|
|
153
159
|
*/
|
|
154
160
|
async getAllServices() {
|
|
161
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
155
162
|
try {
|
|
156
163
|
const services = await this.consul.catalog.service.list();
|
|
157
164
|
return Object.keys(services);
|
|
158
165
|
}
|
|
159
|
-
catch {
|
|
166
|
+
catch (error) {
|
|
167
|
+
logger.error('Failed to list services from Consul', error);
|
|
160
168
|
return [];
|
|
161
169
|
}
|
|
162
170
|
}
|
|
@@ -164,6 +172,7 @@ class ConsulRegistryBackend {
|
|
|
164
172
|
* Update service instance status
|
|
165
173
|
*/
|
|
166
174
|
async updateStatus(instanceId, status) {
|
|
175
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
167
176
|
const checkId = `service:${instanceId}`;
|
|
168
177
|
try {
|
|
169
178
|
if (status === types_1.ServiceStatus.UP) {
|
|
@@ -176,8 +185,8 @@ class ConsulRegistryBackend {
|
|
|
176
185
|
await this.consul.agent.check.warn(checkId);
|
|
177
186
|
}
|
|
178
187
|
}
|
|
179
|
-
catch {
|
|
180
|
-
|
|
188
|
+
catch (error) {
|
|
189
|
+
logger.warn(`Failed to update status for ${instanceId} in Consul`, error);
|
|
181
190
|
}
|
|
182
191
|
}
|
|
183
192
|
/**
|
|
@@ -201,6 +210,7 @@ class ConsulRegistryBackend {
|
|
|
201
210
|
* Start TTL check updates for a service
|
|
202
211
|
*/
|
|
203
212
|
startTTLCheck(instanceId, checkId) {
|
|
213
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
204
214
|
// Parse TTL to get interval (update at 2/3 of TTL)
|
|
205
215
|
const ttlSeconds = this.parseTTL(this.ttl);
|
|
206
216
|
const intervalMs = (ttlSeconds * 1000 * 2) / 3;
|
|
@@ -208,8 +218,8 @@ class ConsulRegistryBackend {
|
|
|
208
218
|
try {
|
|
209
219
|
await this.consul.agent.check.pass(checkId);
|
|
210
220
|
}
|
|
211
|
-
catch {
|
|
212
|
-
|
|
221
|
+
catch (error) {
|
|
222
|
+
logger.warn(`TTL check pass failed for ${instanceId}`, error);
|
|
213
223
|
}
|
|
214
224
|
}, intervalMs);
|
|
215
225
|
this.checkIntervals.set(instanceId, interval);
|
|
@@ -245,31 +255,5 @@ class ConsulRegistryBackend {
|
|
|
245
255
|
return 30;
|
|
246
256
|
}
|
|
247
257
|
}
|
|
248
|
-
/**
|
|
249
|
-
* Apply filter to instances
|
|
250
|
-
*/
|
|
251
|
-
applyFilter(instances, filter) {
|
|
252
|
-
return instances.filter((instance) => {
|
|
253
|
-
if (filter.zone && instance.zone !== filter.zone) {
|
|
254
|
-
return false;
|
|
255
|
-
}
|
|
256
|
-
if (filter.status && instance.status !== filter.status) {
|
|
257
|
-
return false;
|
|
258
|
-
}
|
|
259
|
-
if (filter.tags && filter.tags.length > 0) {
|
|
260
|
-
if (!instance.tags || !filter.tags.every((tag) => instance.tags.includes(tag))) {
|
|
261
|
-
return false;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
if (filter.metadata) {
|
|
265
|
-
for (const [key, value] of Object.entries(filter.metadata)) {
|
|
266
|
-
if (!instance.metadata || instance.metadata[key] !== value) {
|
|
267
|
-
return false;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
return true;
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
258
|
}
|
|
275
259
|
exports.ConsulRegistryBackend = ConsulRegistryBackend;
|
|
@@ -4,7 +4,50 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { RegistryBackend } from './registry-backend';
|
|
6
6
|
import { ServiceInstance, ServiceFilter } from '../types';
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Minimal type definitions for the Kubernetes client API surface we use.
|
|
9
|
+
* These mirror the shapes exposed by `@kubernetes/client-node`.
|
|
10
|
+
*/
|
|
11
|
+
export interface KubeConfig {
|
|
12
|
+
makeApiClient(apiClass: new () => any): any;
|
|
13
|
+
}
|
|
14
|
+
export interface K8sEndpointAddress {
|
|
15
|
+
ip: string;
|
|
16
|
+
targetRef?: {
|
|
17
|
+
name?: string;
|
|
18
|
+
};
|
|
19
|
+
nodeName?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface K8sEndpointPort {
|
|
22
|
+
port: number;
|
|
23
|
+
}
|
|
24
|
+
export interface K8sEndpointSubset {
|
|
25
|
+
ports?: K8sEndpointPort[];
|
|
26
|
+
addresses?: K8sEndpointAddress[];
|
|
27
|
+
notReadyAddresses?: K8sEndpointAddress[];
|
|
28
|
+
}
|
|
29
|
+
export interface K8sObjectMeta {
|
|
30
|
+
name?: string;
|
|
31
|
+
annotations?: Record<string, string>;
|
|
32
|
+
labels?: Record<string, string>;
|
|
33
|
+
creationTimestamp?: string;
|
|
34
|
+
}
|
|
35
|
+
export interface K8sEndpoints {
|
|
36
|
+
metadata?: K8sObjectMeta;
|
|
37
|
+
subsets?: K8sEndpointSubset[];
|
|
38
|
+
}
|
|
39
|
+
export interface K8sService {
|
|
40
|
+
metadata?: K8sObjectMeta;
|
|
41
|
+
}
|
|
42
|
+
export interface K8sApiResponse<T> {
|
|
43
|
+
body: T;
|
|
44
|
+
}
|
|
45
|
+
export interface CoreV1ApiLike {
|
|
46
|
+
readNamespacedEndpoints(name: string, namespace: string): Promise<K8sApiResponse<K8sEndpoints>>;
|
|
47
|
+
listNamespacedService(namespace: string, pretty?: string, allowWatchBookmarks?: boolean, _continue?: string, fieldSelector?: string, labelSelector?: string): Promise<K8sApiResponse<{
|
|
48
|
+
items: K8sService[];
|
|
49
|
+
}>>;
|
|
50
|
+
}
|
|
8
51
|
export interface KubernetesBackendConfig {
|
|
9
52
|
namespace?: string;
|
|
10
53
|
labelSelector?: string;
|
|
@@ -56,10 +99,5 @@ export declare class KubernetesRegistryBackend implements RegistryBackend {
|
|
|
56
99
|
* Create a ServiceInstance from Kubernetes endpoint data
|
|
57
100
|
*/
|
|
58
101
|
private createServiceInstance;
|
|
59
|
-
/**
|
|
60
|
-
* Apply filter to instances
|
|
61
|
-
*/
|
|
62
|
-
private applyFilter;
|
|
63
102
|
}
|
|
64
|
-
export {};
|
|
65
103
|
//# sourceMappingURL=kubernetes-backend.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kubernetes-backend.d.ts","sourceRoot":"","sources":["../../src/backends/kubernetes-backend.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAiB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"kubernetes-backend.d.ts","sourceRoot":"","sources":["../../src/backends/kubernetes-backend.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.KubernetesRegistryBackend = void 0;
|
|
8
8
|
const types_1 = require("../types");
|
|
9
|
+
const filter_1 = require("../utils/filter");
|
|
10
|
+
const logger_1 = require("../utils/logger");
|
|
11
|
+
const validation_1 = require("../utils/validation");
|
|
9
12
|
class KubernetesRegistryBackend {
|
|
10
13
|
constructor(kubeConfig, config = {}) {
|
|
14
|
+
(0, validation_1.validateKubernetesBackendConfig)(config);
|
|
11
15
|
// Import CoreV1Api dynamically to avoid build errors when @kubernetes/client-node is not installed
|
|
12
16
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
13
17
|
const { CoreV1Api: CoreV1ApiClass } = require('@kubernetes/client-node');
|
|
@@ -44,6 +48,7 @@ class KubernetesRegistryBackend {
|
|
|
44
48
|
* Get all instances of a service from Kubernetes Endpoints
|
|
45
49
|
*/
|
|
46
50
|
async getInstances(serviceName, filter) {
|
|
51
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
47
52
|
try {
|
|
48
53
|
// Get service endpoints
|
|
49
54
|
const endpointsResponse = await this.k8sApi.readNamespacedEndpoints(serviceName, this.namespace);
|
|
@@ -73,12 +78,10 @@ class KubernetesRegistryBackend {
|
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
80
|
// Apply filters
|
|
76
|
-
|
|
77
|
-
return this.applyFilter(instances, filter);
|
|
78
|
-
}
|
|
79
|
-
return instances;
|
|
81
|
+
return (0, filter_1.applyServiceFilter)(instances, filter);
|
|
80
82
|
}
|
|
81
|
-
catch {
|
|
83
|
+
catch (error) {
|
|
84
|
+
logger.error(`Failed to get instances for service "${serviceName}" from Kubernetes`, error);
|
|
82
85
|
return [];
|
|
83
86
|
}
|
|
84
87
|
}
|
|
@@ -95,11 +98,13 @@ class KubernetesRegistryBackend {
|
|
|
95
98
|
* Get all registered services in the namespace
|
|
96
99
|
*/
|
|
97
100
|
async getAllServices() {
|
|
101
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
98
102
|
try {
|
|
99
103
|
const servicesResponse = await this.k8sApi.listNamespacedService(this.namespace, undefined, undefined, undefined, undefined, this.labelSelector);
|
|
100
104
|
return servicesResponse.body.items.map((service) => service.metadata?.name || '');
|
|
101
105
|
}
|
|
102
|
-
catch {
|
|
106
|
+
catch (error) {
|
|
107
|
+
logger.error('Failed to list services from Kubernetes', error);
|
|
103
108
|
return [];
|
|
104
109
|
}
|
|
105
110
|
}
|
|
@@ -144,31 +149,5 @@ class KubernetesRegistryBackend {
|
|
|
144
149
|
registeredAt: new Date(metadata?.creationTimestamp || Date.now()),
|
|
145
150
|
};
|
|
146
151
|
}
|
|
147
|
-
/**
|
|
148
|
-
* Apply filter to instances
|
|
149
|
-
*/
|
|
150
|
-
applyFilter(instances, filter) {
|
|
151
|
-
return instances.filter((instance) => {
|
|
152
|
-
if (filter.zone && instance.zone !== filter.zone) {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
if (filter.status && instance.status !== filter.status) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
if (filter.tags && filter.tags.length > 0) {
|
|
159
|
-
if (!instance.tags || !filter.tags.every((tag) => instance.tags.includes(tag))) {
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
if (filter.metadata) {
|
|
164
|
-
for (const [key, value] of Object.entries(filter.metadata)) {
|
|
165
|
-
if (!instance.metadata || instance.metadata[key] !== value) {
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return true;
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
152
|
}
|
|
174
153
|
exports.KubernetesRegistryBackend = KubernetesRegistryBackend;
|
|
@@ -17,6 +17,5 @@ export declare class MemoryRegistryBackend implements RegistryBackend {
|
|
|
17
17
|
getAllServices(): Promise<string[]>;
|
|
18
18
|
updateStatus(instanceId: string, status: string): Promise<void>;
|
|
19
19
|
cleanup(): Promise<void>;
|
|
20
|
-
private applyFilter;
|
|
21
20
|
}
|
|
22
21
|
//# sourceMappingURL=memory-backend.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-backend.d.ts","sourceRoot":"","sources":["../../src/backends/memory-backend.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAiB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"memory-backend.d.ts","sourceRoot":"","sources":["../../src/backends/memory-backend.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAiB,MAAM,UAAU,CAAC;AAGzE,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;gBAE5B,cAAc,SAAQ;IAK5B,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlD,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB7C,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ5C,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAgBrF,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAIhE,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAInC,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAe/B"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.MemoryRegistryBackend = void 0;
|
|
8
8
|
const types_1 = require("../types");
|
|
9
|
+
const filter_1 = require("../utils/filter");
|
|
9
10
|
class MemoryRegistryBackend {
|
|
10
11
|
constructor(expirationTime = 90000) {
|
|
11
12
|
this.instances = new Map();
|
|
@@ -46,7 +47,7 @@ class MemoryRegistryBackend {
|
|
|
46
47
|
const instanceIds = this.serviceIndex.get(serviceName);
|
|
47
48
|
if (!instanceIds)
|
|
48
49
|
return [];
|
|
49
|
-
|
|
50
|
+
const instances = [];
|
|
50
51
|
for (const id of instanceIds) {
|
|
51
52
|
const instance = this.instances.get(id);
|
|
52
53
|
if (instance) {
|
|
@@ -54,10 +55,7 @@ class MemoryRegistryBackend {
|
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
// Apply filters
|
|
57
|
-
|
|
58
|
-
instances = this.applyFilter(instances, filter);
|
|
59
|
-
}
|
|
60
|
-
return instances;
|
|
58
|
+
return (0, filter_1.applyServiceFilter)(instances, filter);
|
|
61
59
|
}
|
|
62
60
|
async getInstance(instanceId) {
|
|
63
61
|
return this.instances.get(instanceId) || null;
|
|
@@ -84,32 +82,5 @@ class MemoryRegistryBackend {
|
|
|
84
82
|
await this.deregister(id);
|
|
85
83
|
}
|
|
86
84
|
}
|
|
87
|
-
applyFilter(instances, filter) {
|
|
88
|
-
return instances.filter((instance) => {
|
|
89
|
-
// Filter by zone
|
|
90
|
-
if (filter.zone && instance.zone !== filter.zone) {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
// Filter by status
|
|
94
|
-
if (filter.status && instance.status !== filter.status) {
|
|
95
|
-
return false;
|
|
96
|
-
}
|
|
97
|
-
// Filter by tags
|
|
98
|
-
if (filter.tags && filter.tags.length > 0) {
|
|
99
|
-
if (!instance.tags || !filter.tags.every((tag) => instance.tags.includes(tag))) {
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
// Filter by metadata
|
|
104
|
-
if (filter.metadata) {
|
|
105
|
-
for (const [key, value] of Object.entries(filter.metadata)) {
|
|
106
|
-
if (!instance.metadata || instance.metadata[key] !== value) {
|
|
107
|
-
return false;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return true;
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
85
|
}
|
|
115
86
|
exports.MemoryRegistryBackend = MemoryRegistryBackend;
|
|
@@ -17,7 +17,16 @@ export declare class RedisRegistryBackend implements RegistryBackend {
|
|
|
17
17
|
private redis;
|
|
18
18
|
private readonly keyPrefix;
|
|
19
19
|
private readonly ttl;
|
|
20
|
+
private connected;
|
|
20
21
|
constructor(redis: Redis, config?: RedisBackendConfig);
|
|
22
|
+
/**
|
|
23
|
+
* Set up Redis connection event handlers for resilience
|
|
24
|
+
*/
|
|
25
|
+
private setupConnectionHandlers;
|
|
26
|
+
/**
|
|
27
|
+
* Check Redis connectivity before operations
|
|
28
|
+
*/
|
|
29
|
+
private ensureConnected;
|
|
21
30
|
/**
|
|
22
31
|
* Register a service instance
|
|
23
32
|
*/
|
|
@@ -31,7 +40,7 @@ export declare class RedisRegistryBackend implements RegistryBackend {
|
|
|
31
40
|
*/
|
|
32
41
|
heartbeat(instanceId: string): Promise<void>;
|
|
33
42
|
/**
|
|
34
|
-
* Get all instances of a service
|
|
43
|
+
* Get all instances of a service (uses MGET for efficiency)
|
|
35
44
|
*/
|
|
36
45
|
getInstances(serviceName: string, filter?: ServiceFilter): Promise<ServiceInstance[]>;
|
|
37
46
|
/**
|
|
@@ -39,7 +48,7 @@ export declare class RedisRegistryBackend implements RegistryBackend {
|
|
|
39
48
|
*/
|
|
40
49
|
getInstance(instanceId: string): Promise<ServiceInstance | null>;
|
|
41
50
|
/**
|
|
42
|
-
* Get all registered services
|
|
51
|
+
* Get all registered services using SCAN (safe for production)
|
|
43
52
|
*/
|
|
44
53
|
getAllServices(): Promise<string[]>;
|
|
45
54
|
/**
|
|
@@ -63,9 +72,5 @@ export declare class RedisRegistryBackend implements RegistryBackend {
|
|
|
63
72
|
* Get Redis key for service set
|
|
64
73
|
*/
|
|
65
74
|
private getServiceSetKey;
|
|
66
|
-
/**
|
|
67
|
-
* Apply filter to instances
|
|
68
|
-
*/
|
|
69
|
-
private applyFilter;
|
|
70
75
|
}
|
|
71
76
|
//# sourceMappingURL=redis-backend.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-backend.d.ts","sourceRoot":"","sources":["../../src/backends/redis-backend.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAiB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"redis-backend.d.ts","sourceRoot":"","sources":["../../src/backends/redis-backend.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAiB,MAAM,UAAU,CAAC;AAIzE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,SAAS,CAAQ;gBAEb,KAAK,EAAE,KAAK,EAAE,MAAM,GAAE,kBAAuB;IAUzD;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAuB/B;;OAEG;IACH,OAAO,CAAC,eAAe;IAMvB;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBxD;;OAEG;IACG,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBnD;;OAEG;IACG,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBlD;;OAEG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA8B3F;;OAEG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAmBtE;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAoBzC;;OAEG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcrE;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA6B9B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAGzB"}
|
|
@@ -6,16 +6,52 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.RedisRegistryBackend = void 0;
|
|
8
8
|
const types_1 = require("../types");
|
|
9
|
+
const filter_1 = require("../utils/filter");
|
|
10
|
+
const logger_1 = require("../utils/logger");
|
|
11
|
+
const validation_1 = require("../utils/validation");
|
|
9
12
|
class RedisRegistryBackend {
|
|
10
13
|
constructor(redis, config = {}) {
|
|
14
|
+
this.connected = true;
|
|
15
|
+
(0, validation_1.validateRedisBackendConfig)(config);
|
|
11
16
|
this.redis = redis;
|
|
12
17
|
this.keyPrefix = config.keyPrefix || 'hazeljs:discovery:';
|
|
13
18
|
this.ttl = config.ttl || 90; // 90 seconds default
|
|
19
|
+
this.setupConnectionHandlers();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Set up Redis connection event handlers for resilience
|
|
23
|
+
*/
|
|
24
|
+
setupConnectionHandlers() {
|
|
25
|
+
const logger = logger_1.DiscoveryLogger.getLogger();
|
|
26
|
+
this.redis.on('error', (err) => {
|
|
27
|
+
this.connected = false;
|
|
28
|
+
logger.error('Redis connection error', err);
|
|
29
|
+
});
|
|
30
|
+
this.redis.on('connect', () => {
|
|
31
|
+
this.connected = true;
|
|
32
|
+
logger.info('Redis connected');
|
|
33
|
+
});
|
|
34
|
+
this.redis.on('reconnecting', () => {
|
|
35
|
+
logger.warn('Redis reconnecting...');
|
|
36
|
+
});
|
|
37
|
+
this.redis.on('close', () => {
|
|
38
|
+
this.connected = false;
|
|
39
|
+
logger.warn('Redis connection closed');
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check Redis connectivity before operations
|
|
44
|
+
*/
|
|
45
|
+
ensureConnected() {
|
|
46
|
+
if (!this.connected) {
|
|
47
|
+
throw new Error('Redis backend is not connected');
|
|
48
|
+
}
|
|
14
49
|
}
|
|
15
50
|
/**
|
|
16
51
|
* Register a service instance
|
|
17
52
|
*/
|
|
18
53
|
async register(instance) {
|
|
54
|
+
this.ensureConnected();
|
|
19
55
|
const key = this.getInstanceKey(instance.id);
|
|
20
56
|
const serviceSetKey = this.getServiceSetKey(instance.name);
|
|
21
57
|
// Store instance data
|
|
@@ -29,6 +65,7 @@ class RedisRegistryBackend {
|
|
|
29
65
|
* Deregister a service instance
|
|
30
66
|
*/
|
|
31
67
|
async deregister(instanceId) {
|
|
68
|
+
this.ensureConnected();
|
|
32
69
|
const key = this.getInstanceKey(instanceId);
|
|
33
70
|
// Get instance to find service name
|
|
34
71
|
const data = await this.redis.get(key);
|
|
@@ -45,6 +82,7 @@ class RedisRegistryBackend {
|
|
|
45
82
|
* Update service instance heartbeat
|
|
46
83
|
*/
|
|
47
84
|
async heartbeat(instanceId) {
|
|
85
|
+
this.ensureConnected();
|
|
48
86
|
const key = this.getInstanceKey(instanceId);
|
|
49
87
|
// Get current instance
|
|
50
88
|
const data = await this.redis.get(key);
|
|
@@ -61,33 +99,36 @@ class RedisRegistryBackend {
|
|
|
61
99
|
}
|
|
62
100
|
}
|
|
63
101
|
/**
|
|
64
|
-
* Get all instances of a service
|
|
102
|
+
* Get all instances of a service (uses MGET for efficiency)
|
|
65
103
|
*/
|
|
66
104
|
async getInstances(serviceName, filter) {
|
|
105
|
+
this.ensureConnected();
|
|
67
106
|
const serviceSetKey = this.getServiceSetKey(serviceName);
|
|
68
107
|
// Get all instance IDs for this service
|
|
69
108
|
const instanceIds = await this.redis.smembers(serviceSetKey);
|
|
70
109
|
if (instanceIds.length === 0) {
|
|
71
110
|
return [];
|
|
72
111
|
}
|
|
73
|
-
//
|
|
112
|
+
// Batch-fetch all instances with MGET
|
|
113
|
+
const keys = instanceIds.map((id) => this.getInstanceKey(id));
|
|
114
|
+
const results = await this.redis.mget(...keys);
|
|
74
115
|
const instances = [];
|
|
75
|
-
for (const
|
|
76
|
-
|
|
77
|
-
|
|
116
|
+
for (const data of results) {
|
|
117
|
+
if (data) {
|
|
118
|
+
const instance = JSON.parse(data);
|
|
119
|
+
instance.lastHeartbeat = new Date(instance.lastHeartbeat);
|
|
120
|
+
instance.registeredAt = new Date(instance.registeredAt);
|
|
78
121
|
instances.push(instance);
|
|
79
122
|
}
|
|
80
123
|
}
|
|
81
124
|
// Apply filters
|
|
82
|
-
|
|
83
|
-
return this.applyFilter(instances, filter);
|
|
84
|
-
}
|
|
85
|
-
return instances;
|
|
125
|
+
return (0, filter_1.applyServiceFilter)(instances, filter);
|
|
86
126
|
}
|
|
87
127
|
/**
|
|
88
128
|
* Get a specific service instance
|
|
89
129
|
*/
|
|
90
130
|
async getInstance(instanceId) {
|
|
131
|
+
this.ensureConnected();
|
|
91
132
|
const key = this.getInstanceKey(instanceId);
|
|
92
133
|
const data = await this.redis.get(key);
|
|
93
134
|
if (!data) {
|
|
@@ -100,20 +141,28 @@ class RedisRegistryBackend {
|
|
|
100
141
|
return instance;
|
|
101
142
|
}
|
|
102
143
|
/**
|
|
103
|
-
* Get all registered services
|
|
144
|
+
* Get all registered services using SCAN (safe for production)
|
|
104
145
|
*/
|
|
105
146
|
async getAllServices() {
|
|
147
|
+
this.ensureConnected();
|
|
106
148
|
const pattern = `${this.keyPrefix}service:*`;
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
149
|
+
const prefixLen = `${this.keyPrefix}service:`.length;
|
|
150
|
+
const services = [];
|
|
151
|
+
let cursor = '0';
|
|
152
|
+
do {
|
|
153
|
+
const [nextCursor, keys] = await this.redis.scan(cursor, 'MATCH', pattern, 'COUNT', 100);
|
|
154
|
+
cursor = nextCursor;
|
|
155
|
+
for (const key of keys) {
|
|
156
|
+
services.push(key.substring(prefixLen));
|
|
157
|
+
}
|
|
158
|
+
} while (cursor !== '0');
|
|
159
|
+
return services;
|
|
112
160
|
}
|
|
113
161
|
/**
|
|
114
162
|
* Update service instance status
|
|
115
163
|
*/
|
|
116
164
|
async updateStatus(instanceId, status) {
|
|
165
|
+
this.ensureConnected();
|
|
117
166
|
const key = this.getInstanceKey(instanceId);
|
|
118
167
|
const data = await this.redis.get(key);
|
|
119
168
|
if (data) {
|
|
@@ -127,8 +176,9 @@ class RedisRegistryBackend {
|
|
|
127
176
|
* Note: Redis handles expiration automatically via TTL
|
|
128
177
|
*/
|
|
129
178
|
async cleanup() {
|
|
179
|
+
this.ensureConnected();
|
|
130
180
|
// Redis automatically removes expired keys
|
|
131
|
-
// This method
|
|
181
|
+
// This method cleans up stale entries in service sets
|
|
132
182
|
const services = await this.getAllServices();
|
|
133
183
|
for (const serviceName of services) {
|
|
134
184
|
const serviceSetKey = this.getServiceSetKey(serviceName);
|
|
@@ -166,35 +216,5 @@ class RedisRegistryBackend {
|
|
|
166
216
|
getServiceSetKey(serviceName) {
|
|
167
217
|
return `${this.keyPrefix}service:${serviceName}`;
|
|
168
218
|
}
|
|
169
|
-
/**
|
|
170
|
-
* Apply filter to instances
|
|
171
|
-
*/
|
|
172
|
-
applyFilter(instances, filter) {
|
|
173
|
-
return instances.filter((instance) => {
|
|
174
|
-
// Filter by zone
|
|
175
|
-
if (filter.zone && instance.zone !== filter.zone) {
|
|
176
|
-
return false;
|
|
177
|
-
}
|
|
178
|
-
// Filter by status
|
|
179
|
-
if (filter.status && instance.status !== filter.status) {
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
// Filter by tags
|
|
183
|
-
if (filter.tags && filter.tags.length > 0) {
|
|
184
|
-
if (!instance.tags || !filter.tags.every((tag) => instance.tags.includes(tag))) {
|
|
185
|
-
return false;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
// Filter by metadata
|
|
189
|
-
if (filter.metadata) {
|
|
190
|
-
for (const [key, value] of Object.entries(filter.metadata)) {
|
|
191
|
-
if (!instance.metadata || instance.metadata[key] !== value) {
|
|
192
|
-
return false;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return true;
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
219
|
}
|
|
200
220
|
exports.RedisRegistryBackend = RedisRegistryBackend;
|
|
@@ -10,6 +10,7 @@ export declare class DiscoveryClient {
|
|
|
10
10
|
private backend;
|
|
11
11
|
private cache;
|
|
12
12
|
private loadBalancerFactory;
|
|
13
|
+
private refreshIntervalHandle;
|
|
13
14
|
constructor(config?: DiscoveryClientConfig, backend?: RegistryBackend);
|
|
14
15
|
/**
|
|
15
16
|
* Get all instances of a service
|
|
@@ -36,12 +37,13 @@ export declare class DiscoveryClient {
|
|
|
36
37
|
*/
|
|
37
38
|
getLoadBalancerFactory(): LoadBalancerFactory;
|
|
38
39
|
/**
|
|
39
|
-
*
|
|
40
|
+
* Close the discovery client and release all resources.
|
|
41
|
+
* Stops the cache refresh interval and clears the cache.
|
|
40
42
|
*/
|
|
41
|
-
|
|
43
|
+
close(): void;
|
|
42
44
|
/**
|
|
43
|
-
*
|
|
45
|
+
* Start cache refresh interval
|
|
44
46
|
*/
|
|
45
|
-
private
|
|
47
|
+
private startRefreshInterval;
|
|
46
48
|
}
|
|
47
49
|
//# sourceMappingURL=discovery-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery-client.d.ts","sourceRoot":"","sources":["../../src/client/discovery-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"discovery-client.d.ts","sourceRoot":"","sources":["../../src/client/discovery-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAKlE,qBAAa,eAAe;IAOxB,OAAO,CAAC,MAAM;IANhB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,KAAK,CAA0E;IACvF,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,qBAAqB,CAA+B;gBAGlD,MAAM,GAAE,qBAA0B,EAC1C,OAAO,CAAC,EAAE,eAAe;IAY3B;;OAEG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA2B3F;;OAEG;IACG,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,QAAQ,GAAE,MAAsB,EAChC,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAQlC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAIzC;;OAEG;IACH,UAAU,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAQtC;;OAEG;IACH,UAAU,IAAI,eAAe;IAI7B;;OAEG;IACH,sBAAsB,IAAI,mBAAmB;IAI7C;;;OAGG;IACH,KAAK,IAAI,IAAI;IAQb;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAkB7B"}
|