@onlineapps/conn-orch-registry 1.1.54 → 1.2.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/README.md +12 -8
- package/docs/REGISTRY_CLIENT_GUIDE.md +15 -24
- package/examples/basicUsage.js +48 -21
- package/examples/event-consumer-example.js +18 -18
- package/package.json +2 -2
- package/src/events.js +15 -8
- package/src/registryClient.js +32 -68
package/README.md
CHANGED
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
[](https://codecov.io/gh/onlineapps/conn-orch-registry)
|
|
5
5
|
[](https://www.npmjs.com/package/@onlineapps/conn-orch-registry)
|
|
6
6
|
|
|
7
|
-
> A lightweight client for microservice registration
|
|
7
|
+
> A lightweight client for microservice registration and heartbeat over RabbitMQ.
|
|
8
|
+
> Sends the full service specification (including `operations`) in the `register`
|
|
9
|
+
> message — see [operations-registry-contract.md §2](../../../docs/standards/operations-registry-contract.md).
|
|
8
10
|
|
|
9
11
|
## 🚀 Features
|
|
10
12
|
|
|
11
13
|
* Automatic queue management (`workflow`, `<serviceName>.registry`, `api_services_queuer`, `registry.register`)
|
|
12
14
|
* Periodic heartbeat messages with metadata
|
|
13
|
-
*
|
|
15
|
+
* Full specification (endpoints + operations) published inside `register`
|
|
14
16
|
* Event-driven API using `EventEmitter`
|
|
15
17
|
* Fully configurable via environment variables or constructor options
|
|
16
18
|
|
|
@@ -35,14 +37,16 @@ const client = new ServiceRegistryClient({
|
|
|
35
37
|
version: '1.0.0'
|
|
36
38
|
});
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
await client.init();
|
|
41
|
+
|
|
42
|
+
// Publish full service spec in the register message (single round-trip).
|
|
43
|
+
await client.register({
|
|
44
|
+
endpoints: [/* ... */],
|
|
45
|
+
operations: await loadOperationsJson(), // see operations-registry-contract.md §3
|
|
46
|
+
metadata: { /* ... */ },
|
|
47
|
+
health: '/health'
|
|
42
48
|
});
|
|
43
49
|
|
|
44
|
-
// Initialize and start heartbeats
|
|
45
|
-
await client.init();
|
|
46
50
|
client.startHeartbeat();
|
|
47
51
|
|
|
48
52
|
// Graceful shutdown
|
|
@@ -17,20 +17,22 @@ Microservice Registry Backend
|
|
|
17
17
|
| (setup connection) | |
|
|
18
18
|
| | |
|
|
19
19
|
|-- register() ----------->| |
|
|
20
|
-
| (
|
|
21
|
-
|
|
|
20
|
+
| (full spec: endpoints | |
|
|
21
|
+
| + operations + meta) |-- validate() --------->|
|
|
22
22
|
| | (check if tested) |
|
|
23
23
|
| |<-- validation result --|
|
|
24
24
|
| | |
|
|
25
|
-
|<--
|
|
25
|
+
|<-- register.confirmed ---| |
|
|
26
26
|
| | |
|
|
27
27
|
|-- startHeartbeat() ----->| |
|
|
28
28
|
| (if validated OK) | |
|
|
29
|
-
| | |
|
|
30
|
-
|-- sendApiDescription() ->| |
|
|
31
|
-
| (on request) | |
|
|
32
29
|
```
|
|
33
30
|
|
|
31
|
+
> The legacy `apiDescriptionRequest` / `sendApiDescription` round-trip has
|
|
32
|
+
> been removed — the full service specification (including the `operations`
|
|
33
|
+
> map) travels as part of the `register` message. See
|
|
34
|
+
> [operations-registry-contract.md §2](../../../../docs/standards/operations-registry-contract.md).
|
|
35
|
+
|
|
34
36
|
## Usage
|
|
35
37
|
|
|
36
38
|
### 1. Basic Setup
|
|
@@ -83,17 +85,7 @@ async function initializeService() {
|
|
|
83
85
|
}
|
|
84
86
|
```
|
|
85
87
|
|
|
86
|
-
### 3.
|
|
87
|
-
|
|
88
|
-
```javascript
|
|
89
|
-
// Listen for requests to send API specification
|
|
90
|
-
registryClient.on('apiDescriptionRequest', async (request) => {
|
|
91
|
-
const apiSpec = await loadApiSpecification();
|
|
92
|
-
await registryClient.sendApiDescription(apiSpec);
|
|
93
|
-
});
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### 4. Event Subscription (Optional)
|
|
88
|
+
### 3. Event Subscription (Optional)
|
|
97
89
|
|
|
98
90
|
For services that need to be notified about registry changes:
|
|
99
91
|
|
|
@@ -132,13 +124,14 @@ async function shutdown() {
|
|
|
132
124
|
Initializes the connection to RabbitMQ and sets up queues.
|
|
133
125
|
|
|
134
126
|
#### `async register(serviceInfo)`
|
|
135
|
-
Registers the service with the registry. The registry
|
|
127
|
+
Registers the service with the registry. The registry validates the service
|
|
128
|
+
against the Operations Registry contract and either confirms or rejects.
|
|
136
129
|
|
|
137
130
|
**Parameters:**
|
|
138
131
|
- `serviceInfo.endpoints` - Array of API endpoints
|
|
132
|
+
- `serviceInfo.operations` - Operations map (see [operations-registry-contract.md §3](../../../../docs/standards/operations-registry-contract.md))
|
|
139
133
|
- `serviceInfo.metadata` - Service metadata object
|
|
140
134
|
- `serviceInfo.health` - Health check endpoint
|
|
141
|
-
- `serviceInfo.spec` - OpenAPI specification (optional)
|
|
142
135
|
|
|
143
136
|
**Returns:** Registration result object with `success` status
|
|
144
137
|
|
|
@@ -148,9 +141,6 @@ Starts sending periodic heartbeat messages. Should only be called after successf
|
|
|
148
141
|
#### `stopHeartbeat()`
|
|
149
142
|
Stops the heartbeat timer.
|
|
150
143
|
|
|
151
|
-
#### `async sendApiDescription(description)`
|
|
152
|
-
Sends the API specification to the registry when requested.
|
|
153
|
-
|
|
154
144
|
#### `async subscribeToChanges()`
|
|
155
145
|
Subscribes to registry change events (optional).
|
|
156
146
|
|
|
@@ -162,9 +152,10 @@ Closes all connections and cleans up resources.
|
|
|
162
152
|
| Event | Payload | Description |
|
|
163
153
|
|-------|---------|-------------|
|
|
164
154
|
| `registerSent` | Registration message | Emitted when registration is sent |
|
|
155
|
+
| `registerConfirmed` | Confirmation payload | Registry accepted the registration |
|
|
156
|
+
| `registerRejected` | Rejection payload | Registry rejected the registration |
|
|
165
157
|
| `heartbeatSent` | Heartbeat message | Emitted on each heartbeat |
|
|
166
|
-
| `
|
|
167
|
-
| `apiDescriptionSent` | Description message | API spec was sent |
|
|
158
|
+
| `revalidate` | Request payload | Registry asks service to revalidate |
|
|
168
159
|
| `error` | Error object | Error occurred |
|
|
169
160
|
|
|
170
161
|
## Registration Validation
|
package/examples/basicUsage.js
CHANGED
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
* Example demonstrating full lifecycle of ServiceRegistryClient:
|
|
5
5
|
* 1. Load environment variables
|
|
6
6
|
* 2. Instantiate client
|
|
7
|
-
* 3. Initialize (setup queues and start listening for
|
|
8
|
-
* 4. Register
|
|
7
|
+
* 3. Initialize (setup queues and start listening for responses)
|
|
8
|
+
* 4. Register with the full service specification (endpoints + operations)
|
|
9
9
|
* 5. Start heartbeat loop
|
|
10
10
|
* 6. Graceful shutdown on process signals
|
|
11
|
+
*
|
|
12
|
+
* See: api/docs/standards/operations-registry-contract.md §2 MQ wire format
|
|
11
13
|
*/
|
|
12
14
|
|
|
13
15
|
function requireEnv(name, description) {
|
|
@@ -20,7 +22,6 @@ function requireEnv(name, description) {
|
|
|
20
22
|
|
|
21
23
|
const { ServiceRegistryClient, EVENTS } = require('@onlineapps/connector-registry-client');
|
|
22
24
|
|
|
23
|
-
// Step 1: Create a new ServiceRegistryClient instance
|
|
24
25
|
const registryClient = new ServiceRegistryClient({
|
|
25
26
|
amqpUrl: requireEnv('AMQP_URL', 'RabbitMQ URL (IPv4-only recommended: amqp://user:pass@127.0.0.1:PORT)'),
|
|
26
27
|
serviceName: requireEnv('SERVICE_NAME', 'Service logical name'),
|
|
@@ -31,20 +32,20 @@ const registryClient = new ServiceRegistryClient({
|
|
|
31
32
|
registryQueue: process.env.REGISTRY_QUEUE
|
|
32
33
|
});
|
|
33
34
|
|
|
34
|
-
// Step 2: Register event listeners
|
|
35
35
|
registryClient.on(EVENTS.HEARTBEAT_SENT, (msg) => {
|
|
36
36
|
console.log(`[Heartbeat] Sent at ${msg.timestamp} for ${msg.serviceName}@${msg.version}`);
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
registryClient.on(EVENTS.
|
|
40
|
-
console.log(`[
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
registryClient.on(EVENTS.REGISTER_CONFIRMED, (msg) => {
|
|
40
|
+
console.log(`[Register] Confirmed for ${msg.serviceName || registryClient.serviceName}`);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
registryClient.on(EVENTS.REGISTER_REJECTED, (msg) => {
|
|
44
|
+
console.error('[Register] Rejected', msg);
|
|
44
45
|
});
|
|
45
46
|
|
|
46
|
-
registryClient.on(EVENTS.
|
|
47
|
-
console.log(
|
|
47
|
+
registryClient.on(EVENTS.REVALIDATE, (payload) => {
|
|
48
|
+
console.log('[Revalidate] Registry asked us to revalidate', payload.reason);
|
|
48
49
|
});
|
|
49
50
|
|
|
50
51
|
registryClient.on(EVENTS.ERROR, (err) => {
|
|
@@ -53,15 +54,15 @@ registryClient.on(EVENTS.ERROR, (err) => {
|
|
|
53
54
|
|
|
54
55
|
(async () => {
|
|
55
56
|
try {
|
|
56
|
-
// Step 3: Initialize client (setup queues and listeners)
|
|
57
57
|
await registryClient.init();
|
|
58
58
|
console.log('RegistryClient initialized: queues are ready.');
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
await registryClient.register(await loadServiceSpec());
|
|
61
|
+
console.log('Register message published.');
|
|
62
|
+
|
|
61
63
|
registryClient.startHeartbeat();
|
|
62
64
|
console.log('Heartbeat loop started.');
|
|
63
65
|
|
|
64
|
-
// Step 5: Graceful shutdown on SIGINT/SIGTERM
|
|
65
66
|
const shutdown = async () => {
|
|
66
67
|
console.log('Shutting down RegistryClient...');
|
|
67
68
|
await registryClient.close();
|
|
@@ -76,15 +77,41 @@ registryClient.on(EVENTS.ERROR, (err) => {
|
|
|
76
77
|
})();
|
|
77
78
|
|
|
78
79
|
/**
|
|
79
|
-
* Helper:
|
|
80
|
-
* In a real
|
|
81
|
-
*
|
|
80
|
+
* Helper: assemble the service specification published in the register message.
|
|
81
|
+
* In a real service this is typically loaded from config/service/operations.json
|
|
82
|
+
* plus the endpoint manifest.
|
|
83
|
+
*
|
|
84
|
+
* @see api/docs/standards/operations-registry-contract.md §3 Operation schema
|
|
82
85
|
*/
|
|
83
|
-
async function
|
|
86
|
+
async function loadServiceSpec() {
|
|
84
87
|
return {
|
|
85
88
|
endpoints: [
|
|
86
|
-
{ path: '/invoices', method: 'POST'
|
|
87
|
-
{ path: '/invoices/:id', method: 'GET'
|
|
88
|
-
]
|
|
89
|
+
{ path: '/invoices', method: 'POST' },
|
|
90
|
+
{ path: '/invoices/:id', method: 'GET' }
|
|
91
|
+
],
|
|
92
|
+
operations: {
|
|
93
|
+
'create-invoice': {
|
|
94
|
+
description: 'Create a new invoice',
|
|
95
|
+
endpoint: '/invoices',
|
|
96
|
+
method: 'POST',
|
|
97
|
+
mutates: true,
|
|
98
|
+
resource_type: 'invoice',
|
|
99
|
+
minRole: 'EDITOR',
|
|
100
|
+
input: {},
|
|
101
|
+
output: {}
|
|
102
|
+
},
|
|
103
|
+
'get-invoice': {
|
|
104
|
+
description: 'Retrieve invoice by ID',
|
|
105
|
+
endpoint: '/invoices/:id',
|
|
106
|
+
method: 'GET',
|
|
107
|
+
mutates: false,
|
|
108
|
+
resource_type: null,
|
|
109
|
+
minRole: 'VIEWER',
|
|
110
|
+
input: {},
|
|
111
|
+
output: {}
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
metadata: {},
|
|
115
|
+
health: '/health'
|
|
89
116
|
};
|
|
90
117
|
}
|
|
@@ -32,25 +32,25 @@ async function main() {
|
|
|
32
32
|
// Initialize connection
|
|
33
33
|
await client.init();
|
|
34
34
|
|
|
35
|
-
// Register ourselves with registry
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
}
|
|
35
|
+
// Register ourselves with the registry. The full spec (endpoints +
|
|
36
|
+
// operations) is published as part of the register message — see
|
|
37
|
+
// api/docs/standards/operations-registry-contract.md §2.
|
|
38
|
+
await client.register({
|
|
39
|
+
endpoints: [{ path: '/hello', method: 'GET' }],
|
|
40
|
+
operations: {
|
|
41
|
+
'say-hello': {
|
|
42
|
+
description: 'Say hello',
|
|
43
|
+
endpoint: '/hello',
|
|
44
|
+
method: 'GET',
|
|
45
|
+
mutates: false,
|
|
46
|
+
resource_type: null,
|
|
47
|
+
minRole: 'VIEWER',
|
|
48
|
+
input: {},
|
|
49
|
+
output: {}
|
|
52
50
|
}
|
|
53
|
-
}
|
|
51
|
+
},
|
|
52
|
+
metadata: {},
|
|
53
|
+
health: '/health'
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
// Start heartbeat
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/conn-orch-registry",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Connector-registry-client provides the core communication mechanism for microservices in this environment. It enables them to interact with a services_registry to receive and fulfill tasks by submitting heartbeats or their API descriptions.",
|
|
6
6
|
"keywords": [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@onlineapps/conn-base-storage": "1.0.9",
|
|
42
|
-
"@onlineapps/mq-client-core": "1.0.
|
|
42
|
+
"@onlineapps/mq-client-core": "1.0.83",
|
|
43
43
|
"@onlineapps/runtime-config": "1.0.2",
|
|
44
44
|
"amqplib": "^0.10.9",
|
|
45
45
|
"axios": "^1.12.2",
|
package/src/events.js
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* Acts as a central place for constants to avoid typos
|
|
6
6
|
* when emitting and listening for events.
|
|
7
7
|
*
|
|
8
|
+
* Legacy `apiDescriptionRequest` / `apiDescriptionSent` events were removed —
|
|
9
|
+
* the full service specification travels as part of the `register` message.
|
|
10
|
+
*
|
|
11
|
+
* @see api/docs/standards/operations-registry-contract.md §2 MQ wire format
|
|
8
12
|
* @module @onlineapps/connector-registry-client/src/events
|
|
9
13
|
*/
|
|
10
14
|
|
|
@@ -14,15 +18,18 @@
|
|
|
14
18
|
const EVENTS = {
|
|
15
19
|
/** Emitted after a successful heartbeat is sent. Payload: { id, type, serviceName, version, timestamp } */
|
|
16
20
|
HEARTBEAT_SENT: 'heartbeatSent',
|
|
17
|
-
|
|
18
|
-
/** Emitted when the
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/** Emitted
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
|
|
22
|
+
/** Emitted when the registry confirms a successful registration. Payload: { requestId, certificate, ... } */
|
|
23
|
+
REGISTER_CONFIRMED: 'registerConfirmed',
|
|
24
|
+
|
|
25
|
+
/** Emitted when the registry rejects a registration. Payload: { requestId, reason, errors, ... } */
|
|
26
|
+
REGISTER_REJECTED: 'registerRejected',
|
|
27
|
+
|
|
28
|
+
/** Emitted when the registry asks the service to revalidate (e.g. infra fingerprint change). */
|
|
29
|
+
REVALIDATE: 'revalidate',
|
|
30
|
+
|
|
24
31
|
/** Emitted on internal errors. Payload: Error instance or error description. */
|
|
25
32
|
ERROR: 'error'
|
|
26
33
|
};
|
|
27
|
-
|
|
34
|
+
|
|
28
35
|
module.exports = EVENTS;
|
package/src/registryClient.js
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* registryClient.js
|
|
3
3
|
*
|
|
4
|
-
* ServiceRegistryClient for communication between a microservice (via Agent)
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* ServiceRegistryClient for communication between a microservice (via Agent)
|
|
5
|
+
* and the central registry. Sends the full service specification in the
|
|
6
|
+
* `register` message (including the `operations` map) and periodic heartbeat
|
|
7
|
+
* messages. Receives registration responses (register.confirmed /
|
|
8
|
+
* register.rejected) and revalidation requests from the registry.
|
|
9
|
+
*
|
|
10
|
+
* Legacy `apiDescription` / `apiDescriptionRequest` round-trips have been
|
|
11
|
+
* removed — the full spec is part of the `register` message itself.
|
|
12
|
+
*
|
|
13
|
+
* Uses QueueManager to manage AMQP queues. Emits events through EventEmitter.
|
|
8
14
|
*
|
|
9
15
|
* Events (see src/events.js):
|
|
10
16
|
* - 'heartbeatSent'
|
|
11
|
-
* - '
|
|
12
|
-
* - '
|
|
17
|
+
* - 'revalidate'
|
|
18
|
+
* - 'registerConfirmed'
|
|
19
|
+
* - 'registerRejected'
|
|
13
20
|
* - 'error'
|
|
14
21
|
*
|
|
22
|
+
* @see api/docs/standards/operations-registry-contract.md §2 MQ wire format
|
|
23
|
+
* @see api/docs/standards/OPERATIONS.md
|
|
24
|
+
*
|
|
15
25
|
* @module @onlineapps/connector-registry-client/src/registryClient
|
|
16
26
|
*/
|
|
17
27
|
|
|
@@ -147,8 +157,7 @@ class ServiceRegistryClient extends EventEmitter {
|
|
|
147
157
|
|
|
148
158
|
/**
|
|
149
159
|
* Internal handler for incoming messages from the registry queue.
|
|
150
|
-
*
|
|
151
|
-
* Handles registration responses.
|
|
160
|
+
* Handles registration responses and revalidation requests.
|
|
152
161
|
* @param {Object} msg - AMQP message
|
|
153
162
|
* @private
|
|
154
163
|
*/
|
|
@@ -181,12 +190,13 @@ class ServiceRegistryClient extends EventEmitter {
|
|
|
181
190
|
return;
|
|
182
191
|
}
|
|
183
192
|
|
|
184
|
-
// Handle
|
|
185
|
-
if (payload.type === '
|
|
186
|
-
|
|
187
|
-
payload.
|
|
188
|
-
|
|
189
|
-
|
|
193
|
+
// Handle revalidation request from registry (infra version change)
|
|
194
|
+
if (payload.type === 'revalidate') {
|
|
195
|
+
console.log(`[RegistryClient] ${this.serviceName}: Received revalidation request`, {
|
|
196
|
+
reason: payload.reason,
|
|
197
|
+
infraFingerprint: payload.infraFingerprint?.substring(0, 16)
|
|
198
|
+
});
|
|
199
|
+
this.emit('revalidate', payload);
|
|
190
200
|
}
|
|
191
201
|
|
|
192
202
|
// Handle registration response from registry
|
|
@@ -376,6 +386,7 @@ class ServiceRegistryClient extends EventEmitter {
|
|
|
376
386
|
}
|
|
377
387
|
|
|
378
388
|
const msgId = uuidv4();
|
|
389
|
+
// @see api/docs/standards/operations-registry-contract.md §2 MQ wire format
|
|
379
390
|
const msg = {
|
|
380
391
|
id: msgId,
|
|
381
392
|
type: 'register',
|
|
@@ -383,6 +394,7 @@ class ServiceRegistryClient extends EventEmitter {
|
|
|
383
394
|
version: this.version,
|
|
384
395
|
specificationEndpoint: this.specificationEndpoint,
|
|
385
396
|
endpoints: serviceInfo.endpoints || [],
|
|
397
|
+
operations: serviceInfo.operations || {},
|
|
386
398
|
metadata: serviceInfo.metadata || {},
|
|
387
399
|
health: serviceInfo.health || '/health',
|
|
388
400
|
spec: serviceInfo.spec || null,
|
|
@@ -392,6 +404,12 @@ class ServiceRegistryClient extends EventEmitter {
|
|
|
392
404
|
timestamp: new Date().toISOString()
|
|
393
405
|
};
|
|
394
406
|
|
|
407
|
+
// Propagate workspaceScoped flag to the registry so consumers can discover
|
|
408
|
+
// which services are workspace-scoped. See biz-service-onboarding.md §4.
|
|
409
|
+
if (typeof serviceInfo.workspaceScoped === 'boolean') {
|
|
410
|
+
msg.workspaceScoped = serviceInfo.workspaceScoped;
|
|
411
|
+
}
|
|
412
|
+
|
|
395
413
|
// Include validation proof if loaded
|
|
396
414
|
// Structure: { validationProof: "hash", validationData: { ... } }
|
|
397
415
|
// See: @onlineapps/service-validator-core/README.md#validation-proof-structure
|
|
@@ -604,60 +622,6 @@ class ServiceRegistryClient extends EventEmitter {
|
|
|
604
622
|
}
|
|
605
623
|
}
|
|
606
624
|
|
|
607
|
-
/**
|
|
608
|
-
* Sends an API description message to the registry queue.
|
|
609
|
-
* Emits 'apiDescriptionSent'.
|
|
610
|
-
* @param {Object} apiDescription - JSON object describing the API
|
|
611
|
-
* @returns {Promise<void>}
|
|
612
|
-
*/
|
|
613
|
-
async sendApiDescription(apiDescription) {
|
|
614
|
-
const msg = {
|
|
615
|
-
id: uuidv4(),
|
|
616
|
-
type: 'apiDescription',
|
|
617
|
-
serviceName: this.serviceName,
|
|
618
|
-
version: this.version,
|
|
619
|
-
description: apiDescription,
|
|
620
|
-
timestamp: new Date().toISOString()
|
|
621
|
-
};
|
|
622
|
-
// CRITICAL: Use queueConfig.js to get correct parameters (TTL, max-length, etc.)
|
|
623
|
-
console.log(`[RegistryClient] [PUBLISH] Preparing to publish to ${this.registryQueue} (apiDescription)`);
|
|
624
|
-
await this._ensureInfrastructureQueue(this.registryQueue);
|
|
625
|
-
this.queueManager.channel.sendToQueue(
|
|
626
|
-
this.registryQueue,
|
|
627
|
-
Buffer.from(JSON.stringify(msg)),
|
|
628
|
-
{ persistent: true }
|
|
629
|
-
);
|
|
630
|
-
this.emit('apiDescriptionSent', msg);
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
/**
|
|
634
|
-
* Alias for sendApiDescription - sends specification to registry
|
|
635
|
-
* @param {Object} spec - API specification (optional, will fetch if not provided)
|
|
636
|
-
* @returns {Promise<void>}
|
|
637
|
-
*/
|
|
638
|
-
async sendSpecification(spec) {
|
|
639
|
-
// If no spec provided, try to fetch it
|
|
640
|
-
if (!spec) {
|
|
641
|
-
try {
|
|
642
|
-
const resolved = runtimeCfg.resolve({ specificationEndpoint: this.specificationEndpoint });
|
|
643
|
-
if (!resolved.servicePort) {
|
|
644
|
-
throw new Error('[RegistryClient] Missing required config - Expected PORT (servicePort) to auto-fetch specification, or pass spec explicitly');
|
|
645
|
-
}
|
|
646
|
-
const url = `${resolved.specProtocol}://${resolved.specHost}:${resolved.servicePort}${resolved.specificationEndpoint}`;
|
|
647
|
-
const response = await fetch(url);
|
|
648
|
-
if (response.ok) {
|
|
649
|
-
spec = await response.json();
|
|
650
|
-
}
|
|
651
|
-
} catch (error) {
|
|
652
|
-
console.error('Failed to fetch specification:', error);
|
|
653
|
-
return;
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
// Use existing method
|
|
658
|
-
return this.sendApiDescription(spec);
|
|
659
|
-
}
|
|
660
|
-
|
|
661
625
|
/**
|
|
662
626
|
* Subscribe to registry change events (opt-in)
|
|
663
627
|
* Creates event consumer and starts listening to registry.changes exchange
|