@onlineapps/service-wrapper 2.1.84 → 2.1.86
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/config/runtime-defaults.json +2 -8
- package/package.json +5 -5
- package/src/ServiceWrapper.js +23 -132
|
@@ -12,14 +12,8 @@
|
|
|
12
12
|
"heartbeatInterval": 30000
|
|
13
13
|
},
|
|
14
14
|
"infrastructureGate": {
|
|
15
|
-
"maxWaitMs":
|
|
16
|
-
"checkIntervalMs":
|
|
17
|
-
},
|
|
18
|
-
"infrastructureVerify": {
|
|
19
|
-
"maxRetries": 12,
|
|
20
|
-
"baseDelayMs": 5000,
|
|
21
|
-
"maxDelayMs": 30000,
|
|
22
|
-
"queueCheckTimeoutMs": 5000
|
|
15
|
+
"maxWaitMs": 5000,
|
|
16
|
+
"checkIntervalMs": 2000
|
|
23
17
|
},
|
|
24
18
|
"monitoring": {
|
|
25
19
|
"enabled": true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/service-wrapper",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.86",
|
|
4
4
|
"description": "Thin orchestration layer for microservices - delegates all infrastructure concerns to specialized connectors",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"@onlineapps/conn-base-cache": "1.0.8",
|
|
28
28
|
"@onlineapps/conn-base-monitoring": "1.0.8",
|
|
29
29
|
"@onlineapps/conn-infra-error-handler": "1.0.7",
|
|
30
|
-
"@onlineapps/conn-infra-mq": "1.1.
|
|
30
|
+
"@onlineapps/conn-infra-mq": "1.1.66",
|
|
31
31
|
"@onlineapps/conn-orch-api-mapper": "1.0.26",
|
|
32
|
-
"@onlineapps/conn-orch-cookbook": "2.0.
|
|
33
|
-
"@onlineapps/conn-orch-orchestrator": "1.0.
|
|
34
|
-
"@onlineapps/conn-orch-registry": "1.1.
|
|
32
|
+
"@onlineapps/conn-orch-cookbook": "2.0.27",
|
|
33
|
+
"@onlineapps/conn-orch-orchestrator": "1.0.90",
|
|
34
|
+
"@onlineapps/conn-orch-registry": "1.1.43",
|
|
35
35
|
"@onlineapps/conn-orch-validator": "2.0.25",
|
|
36
36
|
"@onlineapps/monitoring-core": "1.0.18",
|
|
37
37
|
"@onlineapps/service-common": "1.0.13",
|
package/src/ServiceWrapper.js
CHANGED
|
@@ -935,143 +935,34 @@ class ServiceWrapper {
|
|
|
935
935
|
* 1. Service has certificate (validated + registered) - checked in _startWorkflowListenersIfReady()
|
|
936
936
|
* 2. Infrastructure is ready - checked in this method
|
|
937
937
|
*
|
|
938
|
-
*
|
|
939
|
-
*
|
|
940
|
-
*
|
|
938
|
+
* SEPARATION OF CONCERNS:
|
|
939
|
+
* - Business services MUST NOT check infrastructure queues directly.
|
|
940
|
+
* - Business services MUST trust Registry's infrastructure:health:all flag.
|
|
941
|
+
* - Infrastructure services are responsible for their own queue health.
|
|
942
|
+
* - If infrastructure is not ready within timeout, business service exits (Docker restarts it).
|
|
941
943
|
*
|
|
942
|
-
* Uses exponential backoff retry mechanism if infrastructure not ready.
|
|
943
944
|
* @private
|
|
944
945
|
*/
|
|
945
946
|
async _verifyInfrastructureReady(serviceName) {
|
|
946
|
-
|
|
947
|
-
const baseDelay = this.config.wrapper?.infrastructureVerify?.baseDelayMs;
|
|
948
|
-
const maxDelay = this.config.wrapper?.infrastructureVerify?.maxDelayMs;
|
|
949
|
-
const queueCheckTimeoutMs = this.config.wrapper?.infrastructureVerify?.queueCheckTimeoutMs;
|
|
950
|
-
|
|
951
|
-
if (typeof maxRetries !== 'number' || Number.isNaN(maxRetries) || maxRetries <= 0) {
|
|
952
|
-
throw new Error(`[InfrastructureVerify] Invalid configuration - wrapper.infrastructureVerify.maxRetries must be a positive number, got: ${maxRetries}`);
|
|
953
|
-
}
|
|
954
|
-
if (typeof baseDelay !== 'number' || Number.isNaN(baseDelay) || baseDelay <= 0) {
|
|
955
|
-
throw new Error(`[InfrastructureVerify] Invalid configuration - wrapper.infrastructureVerify.baseDelayMs must be a positive number, got: ${baseDelay}`);
|
|
956
|
-
}
|
|
957
|
-
if (typeof maxDelay !== 'number' || Number.isNaN(maxDelay) || maxDelay <= 0) {
|
|
958
|
-
throw new Error(`[InfrastructureVerify] Invalid configuration - wrapper.infrastructureVerify.maxDelayMs must be a positive number, got: ${maxDelay}`);
|
|
959
|
-
}
|
|
960
|
-
if (typeof queueCheckTimeoutMs !== 'number' || Number.isNaN(queueCheckTimeoutMs) || queueCheckTimeoutMs <= 0) {
|
|
961
|
-
throw new Error(`[InfrastructureVerify] Invalid configuration - wrapper.infrastructureVerify.queueCheckTimeoutMs must be a positive number, got: ${queueCheckTimeoutMs}`);
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
// Required infrastructure queues that must exist before business queues can be created
|
|
965
|
-
const requiredInfrastructureQueues = [
|
|
966
|
-
'workflow.init', // Gateway responsibility (workflow entrypoint)
|
|
967
|
-
'workflow.control', // Gateway responsibility (shared control-flow steps)
|
|
968
|
-
'registry.register', // Registry responsibility
|
|
969
|
-
];
|
|
947
|
+
this.logger?.info('[InfrastructureReady] Checking infrastructure status via Registry (trusting infrastructure:health:all flag)...');
|
|
970
948
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
// Step 2: Verify required infrastructure queues exist
|
|
989
|
-
this.logger?.info('[InfrastructureVerify] Verifying required infrastructure queues exist...');
|
|
990
|
-
|
|
991
|
-
const transport = this.mqClient._transport;
|
|
992
|
-
if (!transport || !transport._queueChannel) {
|
|
993
|
-
throw new Error('MQ transport not initialized - cannot verify infrastructure queues');
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
const channel = transport._queueChannel;
|
|
997
|
-
if (channel.closed) {
|
|
998
|
-
throw new Error('MQ channel is closed - cannot verify infrastructure queues');
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
const missingQueues = [];
|
|
1002
|
-
for (const queueName of requiredInfrastructureQueues) {
|
|
1003
|
-
try {
|
|
1004
|
-
// Add timeout to prevent hanging on checkQueue
|
|
1005
|
-
const checkPromise = channel.checkQueue(queueName);
|
|
1006
|
-
const checkTimeoutPromise = new Promise((_, reject) => {
|
|
1007
|
-
setTimeout(() => {
|
|
1008
|
-
reject(new Error(`checkQueue timeout after ${queueCheckTimeoutMs}ms`));
|
|
1009
|
-
}, queueCheckTimeoutMs);
|
|
1010
|
-
});
|
|
1011
|
-
|
|
1012
|
-
await Promise.race([checkPromise, checkTimeoutPromise]);
|
|
1013
|
-
this.logger?.info(`[InfrastructureVerify] ✓ Queue exists: ${queueName}`);
|
|
1014
|
-
} catch (checkErr) {
|
|
1015
|
-
if (checkErr.code === 404 || checkErr.message.includes('timeout')) {
|
|
1016
|
-
missingQueues.push(queueName);
|
|
1017
|
-
this.logger?.warn(`[InfrastructureVerify] ✗ Queue missing or timeout: ${queueName} (${checkErr.message})`);
|
|
1018
|
-
} else {
|
|
1019
|
-
// Other error (e.g., channel closed) - treat as missing
|
|
1020
|
-
missingQueues.push(queueName);
|
|
1021
|
-
this.logger?.warn(`[InfrastructureVerify] ✗ Cannot check queue ${queueName}: ${checkErr.message}`);
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
if (missingQueues.length > 0) {
|
|
1027
|
-
const queueDetails = missingQueues.map((queueName) => {
|
|
1028
|
-
const owner = INFRA_QUEUE_OWNERS[queueName] || 'responsible infrastructure service';
|
|
1029
|
-
return `${queueName} (owner: ${owner})`;
|
|
1030
|
-
});
|
|
1031
|
-
throw new Error(
|
|
1032
|
-
`[InfrastructureVerify] Required RabbitMQ queue(s) missing: ${queueDetails.join(', ')}. ` +
|
|
1033
|
-
'Infrastructure service(s) responsible for these queues are not ready yet. ' +
|
|
1034
|
-
'Resolve the infrastructure issue and restart the business service.'
|
|
1035
|
-
);
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
// Step 3: Log optional queues status (for debugging)
|
|
1039
|
-
for (const queueName of optionalInfrastructureQueues) {
|
|
1040
|
-
try {
|
|
1041
|
-
const checkPromise = channel.checkQueue(queueName);
|
|
1042
|
-
const checkTimeoutPromise = new Promise((_, reject) => {
|
|
1043
|
-
setTimeout(() => reject(new Error('timeout')), queueCheckTimeoutMs);
|
|
1044
|
-
});
|
|
1045
|
-
await Promise.race([checkPromise, checkTimeoutPromise]);
|
|
1046
|
-
this.logger?.info(`[InfrastructureVerify] ✓ Optional queue exists: ${queueName}`);
|
|
1047
|
-
} catch (checkErr) {
|
|
1048
|
-
if (checkErr.code === 404 || checkErr.message.includes('timeout')) {
|
|
1049
|
-
this.logger?.debug(`[InfrastructureVerify] Optional queue missing or timeout (not critical): ${queueName}`);
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
// All checks passed!
|
|
1055
|
-
this.logger?.info('[InfrastructureVerify] ✓ Infrastructure verification complete - all required queues exist');
|
|
1056
|
-
return;
|
|
1057
|
-
|
|
1058
|
-
} catch (error) {
|
|
1059
|
-
if (attempt === maxRetries) {
|
|
1060
|
-
// Final attempt failed - throw error
|
|
1061
|
-
this.logger?.error('[InfrastructureVerify] ✗ Infrastructure verification failed after all retries', {
|
|
1062
|
-
error: error.message,
|
|
1063
|
-
stack: error.stack
|
|
1064
|
-
});
|
|
1065
|
-
throw new Error(`Infrastructure verification failed for ${serviceName}: ${error.message}`);
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
// Not final attempt - continue retry loop
|
|
1069
|
-
const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxDelay);
|
|
1070
|
-
this.logger?.warn(`[InfrastructureVerify] Verification failed (attempt ${attempt}/${maxRetries}), retrying in ${delay}ms...`, {
|
|
1071
|
-
error: error.message
|
|
1072
|
-
});
|
|
1073
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
1074
|
-
}
|
|
949
|
+
try {
|
|
950
|
+
// Single check - if infra not ready, fail fast and let Docker restart
|
|
951
|
+
await this._waitForInfrastructureGate('business queue setup');
|
|
952
|
+
this.logger?.info('[InfrastructureReady] ✓ Infrastructure is ready (infrastructure:health:all = true)');
|
|
953
|
+
} catch (error) {
|
|
954
|
+
// Infrastructure not ready - fail fast with clear message
|
|
955
|
+
this.logger?.error('[InfrastructureReady] ✗ Infrastructure not ready - service will exit', {
|
|
956
|
+
error: error.message,
|
|
957
|
+
serviceName,
|
|
958
|
+
action: 'Docker will restart the service. Check infrastructure services (Gateway, Registry, Validator, Delivery, Monitoring).'
|
|
959
|
+
});
|
|
960
|
+
throw new Error(
|
|
961
|
+
`[InfrastructureReady] Infrastructure not ready for ${serviceName}. ` +
|
|
962
|
+
'Registry reports infrastructure:health:all != true. ' +
|
|
963
|
+
'Check infrastructure services and their logs. ' +
|
|
964
|
+
'This service will exit and Docker will restart it.'
|
|
965
|
+
);
|
|
1075
966
|
}
|
|
1076
967
|
}
|
|
1077
968
|
|