@mojaloop/sdk-scheme-adapter 24.2.0-csi-1210.5 → 24.2.0
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/.yarn/cache/{@mojaloop-sdk-standard-components-npm-19.9.0-snapshot.2-0f7ee02ccc-9986c1c680.zip → @mojaloop-sdk-standard-components-npm-19.9.0-54f15be12d-042cb3fccc.zip} +0 -0
- package/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +14 -0
- package/docker-compose.yml +10 -5
- package/modules/api-svc/package.json +1 -1
- package/modules/api-svc/src/config.js +2 -1
- package/modules/api-svc/src/index.js +58 -12
- package/modules/api-svc/test/integration-pm4ml/mockServers/managementService/server.js +35 -1
- package/modules/api-svc/test/unit/index.test.js +1 -0
- package/modules/api-svc/test/unit/lib/model/OutboundTransfersModel.test.js +0 -7
- package/package.json +1 -1
|
Binary file
|
package/.yarn/install-state.gz
CHANGED
|
Binary file
|
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
# Changelog: [mojaloop/sdk-scheme-adapter](https://github.com/mojaloop/sdk-scheme-adapter)
|
|
2
|
+
## [24.2.0](https://github.com/mojaloop/sdk-scheme-adapter/compare/v24.1.3...v24.2.0) (2025-03-05)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* add code to restart sdk on broken control client connection ([#555](https://github.com/mojaloop/sdk-scheme-adapter/issues/555)) ([4ce10e8](https://github.com/mojaloop/sdk-scheme-adapter/commit/4ce10e8c1385471e1cf33fc0abe923210167a099))
|
|
8
|
+
* **csi-1210:** added OTel header to Outbound/Inbound TransfersModel ([#552](https://github.com/mojaloop/sdk-scheme-adapter/issues/552)) ([cbbd0b7](https://github.com/mojaloop/sdk-scheme-adapter/commit/cbbd0b7e0e26eb85d04178a1e8cdb2120b9f4f6f))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Chore
|
|
12
|
+
|
|
13
|
+
* add better service checks to docker compose ([#556](https://github.com/mojaloop/sdk-scheme-adapter/issues/556)) ([ba0d7f0](https://github.com/mojaloop/sdk-scheme-adapter/commit/ba0d7f04ba7a138363c85edad5ba0bef0b7e5302))
|
|
14
|
+
* add heartbeat to test server ([#557](https://github.com/mojaloop/sdk-scheme-adapter/issues/557)) ([5d7b628](https://github.com/mojaloop/sdk-scheme-adapter/commit/5d7b6284e93c081359089f6865c726f05d2f44b9))
|
|
15
|
+
|
|
2
16
|
### [24.1.3](https://github.com/mojaloop/sdk-scheme-adapter/compare/v24.1.2...v24.1.3) (2025-02-25)
|
|
3
17
|
|
|
4
18
|
|
package/docker-compose.yml
CHANGED
|
@@ -19,9 +19,12 @@ services:
|
|
|
19
19
|
- "4002:4002"
|
|
20
20
|
- "9229:9229"
|
|
21
21
|
depends_on:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
22
|
+
redis:
|
|
23
|
+
condition: service_healthy
|
|
24
|
+
ml-testing-toolkit:
|
|
25
|
+
condition: service_started
|
|
26
|
+
kafka:
|
|
27
|
+
condition: service_healthy
|
|
25
28
|
command: yarn nx run modules-api-svc:start
|
|
26
29
|
volumes:
|
|
27
30
|
- ./docker/wait4:/tmp/wait4
|
|
@@ -144,7 +147,8 @@ services:
|
|
|
144
147
|
environment:
|
|
145
148
|
- KAFKA_BROKERS=kafka:29092
|
|
146
149
|
depends_on:
|
|
147
|
-
|
|
150
|
+
kafka:
|
|
151
|
+
condition: service_healthy
|
|
148
152
|
profiles:
|
|
149
153
|
- debug
|
|
150
154
|
|
|
@@ -153,7 +157,8 @@ services:
|
|
|
153
157
|
- mojaloop-net
|
|
154
158
|
image: docker.io/bitnami/kafka:3.4.0
|
|
155
159
|
depends_on:
|
|
156
|
-
|
|
160
|
+
kafka:
|
|
161
|
+
condition: service_healthy
|
|
157
162
|
entrypoint: [ '/bin/sh', '-c' ]
|
|
158
163
|
command: |
|
|
159
164
|
"
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"@mojaloop/logging-bc-client-lib": "0.5.8",
|
|
74
74
|
"@mojaloop/ml-schema-transformer-lib": "2.5.6",
|
|
75
75
|
"@mojaloop/sdk-scheme-adapter-private-shared-lib": "workspace:^",
|
|
76
|
-
"@mojaloop/sdk-standard-components": "
|
|
76
|
+
"@mojaloop/sdk-standard-components": "19.9.0",
|
|
77
77
|
"ajv": "8.17.1",
|
|
78
78
|
"axios": "1.8.1",
|
|
79
79
|
"body-parser": "1.20.3",
|
|
@@ -86,7 +86,8 @@ module.exports = {
|
|
|
86
86
|
__parseResourceVersion: parseResourceVersions,
|
|
87
87
|
control: {
|
|
88
88
|
mgmtAPIWsUrl: env.get('MGMT_API_WS_URL').default('127.0.0.1').asString(),
|
|
89
|
-
mgmtAPIWsPort: env.get('MGMT_API_WS_PORT').default('4005').asPortNumber()
|
|
89
|
+
mgmtAPIWsPort: env.get('MGMT_API_WS_PORT').default('4005').asPortNumber(),
|
|
90
|
+
mgmtAPILatencyAssumption: env.get('MGMT_API_LATENCY_ASSUMPTION').default('2000').asIntPositive(),
|
|
90
91
|
},
|
|
91
92
|
idGenerator: env.get('ID_GENERATOR').default('{"type":"ulid"}').asJsonObject(),
|
|
92
93
|
logLevel: env.get('LOG_LEVEL').default('info').asEnum(Logger.logLevels),
|
|
@@ -62,6 +62,8 @@ const LOG_ID = {
|
|
|
62
62
|
CACHE: { component: 'cache' },
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
+
const PING_INTERVAL_MS = 30000;
|
|
66
|
+
|
|
65
67
|
const createCache = (config, logger) => new Cache({
|
|
66
68
|
cacheUrl: config.cacheUrl,
|
|
67
69
|
logger: logger.push(LOG_ID.CACHE),
|
|
@@ -78,6 +80,7 @@ class Server extends EventEmitter {
|
|
|
78
80
|
this.conf = conf;
|
|
79
81
|
this.logger = logger;
|
|
80
82
|
this.cache = createCache(conf, logger);
|
|
83
|
+
this.pingTimeout;
|
|
81
84
|
|
|
82
85
|
this.metricsClient = new MetricsClient();
|
|
83
86
|
|
|
@@ -166,12 +169,33 @@ class Server extends EventEmitter {
|
|
|
166
169
|
appConfig: this.conf,
|
|
167
170
|
});
|
|
168
171
|
this.controlClient.on(ControlAgent.EVENT.RECONFIGURE, this.restart.bind(this));
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
|
|
173
|
+
const schedulePing = () => {
|
|
174
|
+
clearTimeout(this.pingTimeout);
|
|
175
|
+
this.pingTimeout = setTimeout(() => {
|
|
176
|
+
this.logger.error('Ping timeout, possible broken connection. Restarting server...');
|
|
177
|
+
this.restart(_.merge({}, this.conf, {
|
|
178
|
+
control: { stopped: Date.now() }
|
|
179
|
+
}));
|
|
180
|
+
}, PING_INTERVAL_MS + this.conf.control.mgmtAPILatencyAssumption);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
this.controlClient.on('ping', () => {
|
|
184
|
+
this.logger.debug('Received ping from control server');
|
|
185
|
+
schedulePing();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
this.controlClient.on('close', () => {
|
|
189
|
+
clearTimeout(this.pingTimeout);
|
|
190
|
+
setTimeout(() => {
|
|
191
|
+
this.logger.debug('Control client closed. Restarting server...');
|
|
192
|
+
this.restart(_.merge({}, this.conf, {
|
|
193
|
+
control: { stopped: Date.now() }
|
|
194
|
+
}));
|
|
195
|
+
}, RESTART_INTERVAL_MS);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
schedulePing();
|
|
175
199
|
}
|
|
176
200
|
|
|
177
201
|
await Promise.all([
|
|
@@ -284,12 +308,33 @@ class Server extends EventEmitter {
|
|
|
284
308
|
appConfig: newConf,
|
|
285
309
|
});
|
|
286
310
|
this.controlClient.on(ControlAgent.EVENT.RECONFIGURE, this.restart.bind(this));
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
this.
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
311
|
+
|
|
312
|
+
const schedulePing = () => {
|
|
313
|
+
clearTimeout(this.pingTimeout);
|
|
314
|
+
this.pingTimeout = setTimeout(() => {
|
|
315
|
+
this.logger.error('Ping timeout, possible broken connection. Restarting server...');
|
|
316
|
+
this.restart(_.merge({}, newConf, {
|
|
317
|
+
control: { stopped: Date.now() }
|
|
318
|
+
}));
|
|
319
|
+
}, PING_INTERVAL_MS + this.conf.control.mgmtAPILatencyAssumption);
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
this.controlClient.on('ping', () => {
|
|
323
|
+
this.logger.debug('Received ping from control server');
|
|
324
|
+
schedulePing();
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
this.controlClient.on('close', () => {
|
|
328
|
+
clearTimeout(this.pingTimeout);
|
|
329
|
+
setTimeout(() => {
|
|
330
|
+
this.logger.debug('Control client closed. Restarting server...');
|
|
331
|
+
this.restart(_.merge({}, newConf, {
|
|
332
|
+
control: { stopped: Date.now() }
|
|
333
|
+
}));
|
|
334
|
+
}, RESTART_INTERVAL_MS);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
schedulePing();
|
|
293
338
|
restartActionsTaken.updateControlClient = true;
|
|
294
339
|
}
|
|
295
340
|
}
|
|
@@ -337,6 +382,7 @@ class Server extends EventEmitter {
|
|
|
337
382
|
}
|
|
338
383
|
|
|
339
384
|
stop() {
|
|
385
|
+
clearTimeout(this.pingTimeout);
|
|
340
386
|
this.wso2.auth.stop();
|
|
341
387
|
this.controlClient?.removeAllListeners();
|
|
342
388
|
this.inboundServer.removeAllListeners();
|
|
@@ -113,6 +113,7 @@ class Server extends ws.Server {
|
|
|
113
113
|
_clientData;
|
|
114
114
|
_currentConfig;
|
|
115
115
|
_isConfigUpdated;
|
|
116
|
+
_heartbeatInterval;
|
|
116
117
|
|
|
117
118
|
constructor(opts) {
|
|
118
119
|
super({ clientTracking: true, port: opts.port });
|
|
@@ -134,7 +135,14 @@ class Server extends ws.Server {
|
|
|
134
135
|
remoteAddress: req.socket.remoteAddress,
|
|
135
136
|
});
|
|
136
137
|
logger.log('Websocket connection received');
|
|
137
|
-
this._clientData.set(socket, { ip: req.connection.remoteAddress, logger });
|
|
138
|
+
this._clientData.set(socket, { ip: req.connection.remoteAddress, logger, isAlive: true });
|
|
139
|
+
|
|
140
|
+
socket.on('pong', () => {
|
|
141
|
+
const clientData = this._clientData.get(socket);
|
|
142
|
+
if (clientData) {
|
|
143
|
+
clientData.isAlive = true;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
138
146
|
|
|
139
147
|
socket.on('close', (code, reason) => {
|
|
140
148
|
logger.push({ code, reason }).log('Websocket connection closed');
|
|
@@ -144,6 +152,31 @@ class Server extends ws.Server {
|
|
|
144
152
|
socket.on('message', this._handle(socket, logger));
|
|
145
153
|
});
|
|
146
154
|
this._logger.push(this.address()).log('running on');
|
|
155
|
+
this._startHeartbeat();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
_startHeartbeat() {
|
|
159
|
+
this._heartbeatInterval = setInterval(() => {
|
|
160
|
+
this.clients.forEach((client) => {
|
|
161
|
+
const clientData = this._clientData.get(client);
|
|
162
|
+
if (clientData && !clientData.isAlive) {
|
|
163
|
+
client.terminate();
|
|
164
|
+
this._clientData.delete(client);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (clientData) {
|
|
168
|
+
clientData.isAlive = false;
|
|
169
|
+
}
|
|
170
|
+
client.ping();
|
|
171
|
+
});
|
|
172
|
+
}, 30000);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
_stopHeartbeat() {
|
|
176
|
+
if (this._heartbeatInterval) {
|
|
177
|
+
clearInterval(this._heartbeatInterval);
|
|
178
|
+
this._heartbeatInterval = null;
|
|
179
|
+
}
|
|
147
180
|
}
|
|
148
181
|
|
|
149
182
|
_setConfig(newConfig) {
|
|
@@ -158,6 +191,7 @@ class Server extends ws.Server {
|
|
|
158
191
|
|
|
159
192
|
// Close the server then wait for all the client sockets to close
|
|
160
193
|
async stop() {
|
|
194
|
+
this._stopHeartbeat();
|
|
161
195
|
const closing = new Promise((resolve) => this.close(resolve));
|
|
162
196
|
for (const client of this.clients) {
|
|
163
197
|
client.terminate();
|
|
@@ -73,6 +73,7 @@ describe('Server', () => {
|
|
|
73
73
|
conf.control.mgmtAPIWsUrl = 'localhost';
|
|
74
74
|
conf.control.mgmtAPIWsPort = 4005;
|
|
75
75
|
conf.control.port = conf.control.mgmtAPIWsPort;
|
|
76
|
+
conf.control.mgmtAPILatencyAssumption = 2000;
|
|
76
77
|
controlServer = new TestControlServer.Server({ logger, appConfig: conf });
|
|
77
78
|
server = new index.Server(conf, logger);
|
|
78
79
|
server.restart = jest.fn();
|
|
@@ -221,13 +221,6 @@ describe('OutboundTransfersModel Tests', () => {
|
|
|
221
221
|
expect(model.data.traceId.length).toBe(32);
|
|
222
222
|
});
|
|
223
223
|
|
|
224
|
-
// test('should generate traceId based on transferId value', async () => {
|
|
225
|
-
// const model = await createAndInitModel();
|
|
226
|
-
// expect(model.data.transferId.length).toBe(26);
|
|
227
|
-
// expect(model.data.traceId.length).toBe(32);
|
|
228
|
-
// // todo: check traceID value
|
|
229
|
-
// });
|
|
230
|
-
|
|
231
224
|
test('executes all three transfer stages without halting when AUTO_ACCEPT_PARTY and AUTO_ACCEPT_QUOTES are true', async () => {
|
|
232
225
|
config.autoAcceptParty = true;
|
|
233
226
|
config.autoAcceptQuotes = true;
|
package/package.json
CHANGED