@onlineapps/service-common 1.0.7 → 1.0.9
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/package.json +1 -1
- package/src/config.js +20 -7
- package/src/defaults.js +9 -5
- package/src/index.js +1 -5
- package/src/infrastructure/waitForHealthCheckQueueReady.js +5 -7
- package/src/infrastructure/waitForInfrastructureReady.js +5 -7
- package/src/redisClient.js +23 -24
- package/src/reporting/monitoringFallbackEmail.js +8 -7
- package/src/runtime-config.js +43 -97
- package/tests/unit/defaults.test.js +11 -8
- package/onlineapps-service-common-1.0.1.tgz +0 -0
package/package.json
CHANGED
package/src/config.js
CHANGED
|
@@ -23,16 +23,29 @@ const DEFAULTS = require('./defaults');
|
|
|
23
23
|
const runtimeCfg = createRuntimeConfig({
|
|
24
24
|
defaults: DEFAULTS,
|
|
25
25
|
schema: {
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
redisUrl: { env: 'REDIS_URL', defaultKey: 'redisUrl' },
|
|
30
|
-
|
|
31
|
-
// RabbitMQ defaults
|
|
32
|
-
rabbitmqUrl: { env: 'RABBITMQ_URL', defaultKey: 'rabbitmqUrl' },
|
|
26
|
+
// Infrastructure topology (FAIL-FAST, no defaults)
|
|
27
|
+
redisUrl: { env: 'REDIS_URL', required: true },
|
|
28
|
+
rabbitmqUrl: { env: 'RABBITMQ_URL', required: true },
|
|
33
29
|
|
|
34
30
|
// Infrastructure health
|
|
35
31
|
infrastructureHealthQueueName: { env: 'INFRASTRUCTURE_HEALTH_QUEUE', defaultKey: 'infrastructureHealthQueueName' },
|
|
32
|
+
infrastructureHealthPublishIntervalMs: { env: 'INFRASTRUCTURE_HEALTH_PUBLISH_INTERVAL', defaultKey: 'infrastructureHealthPublishIntervalMs', type: 'number' },
|
|
33
|
+
infrastructureHealthWaitMaxTimeMs: { env: 'INFRASTRUCTURE_HEALTH_WAIT_MAX_TIME', defaultKey: 'infrastructureHealthWaitMaxTimeMs', type: 'number' },
|
|
34
|
+
infrastructureHealthWaitCheckIntervalMs: { env: 'INFRASTRUCTURE_HEALTH_WAIT_CHECK_INTERVAL', defaultKey: 'infrastructureHealthWaitCheckIntervalMs', type: 'number' },
|
|
35
|
+
infrastructureHealthTimeoutMs: { env: 'INFRASTRUCTURE_HEALTH_TIMEOUT', defaultKey: 'infrastructureHealthTimeoutMs', type: 'number' },
|
|
36
|
+
infrastructureHealthRedisTtlSeconds: { env: 'INFRASTRUCTURE_HEALTH_REDIS_TTL', defaultKey: 'infrastructureHealthRedisTtlSeconds', type: 'number' },
|
|
37
|
+
infrastructureHealthCleanupIntervalMs: { env: 'INFRASTRUCTURE_HEALTH_CLEANUP_INTERVAL', defaultKey: 'infrastructureHealthCleanupIntervalMs', type: 'number' },
|
|
38
|
+
infrastructureHealthQueueWaitMaxTimeMs: { env: 'INFRASTRUCTURE_HEALTH_QUEUE_WAIT_MAX_TIME', defaultKey: 'infrastructureHealthQueueWaitMaxTimeMs', type: 'number' },
|
|
39
|
+
infrastructureHealthQueueWaitCheckIntervalMs: { env: 'INFRASTRUCTURE_HEALTH_QUEUE_WAIT_CHECK_INTERVAL', defaultKey: 'infrastructureHealthQueueWaitCheckIntervalMs', type: 'number' },
|
|
40
|
+
|
|
41
|
+
// Optional reporting (no defaults; feature is disabled unless fully configured)
|
|
42
|
+
infraReportSmtpHost: { env: 'INFRA_REPORT_SMTP_HOST' },
|
|
43
|
+
infraReportSmtpPort: { env: 'INFRA_REPORT_SMTP_PORT', type: 'number' },
|
|
44
|
+
infraReportSmtpSecure: { env: 'INFRA_REPORT_SMTP_SECURE', type: 'boolean' },
|
|
45
|
+
infraReportSmtpUser: { env: 'INFRA_REPORT_SMTP_USER' },
|
|
46
|
+
infraReportSmtpPass: { env: 'INFRA_REPORT_SMTP_PASS' },
|
|
47
|
+
infraReportFrom: { env: 'INFRA_REPORT_FROM' },
|
|
48
|
+
infraReportTo: { env: 'INFRA_REPORT_TO' },
|
|
36
49
|
}
|
|
37
50
|
});
|
|
38
51
|
|
package/src/defaults.js
CHANGED
|
@@ -10,12 +10,16 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
module.exports = {
|
|
13
|
-
redisHost: 'api_node_cache',
|
|
14
|
-
redisPort: '6379',
|
|
15
|
-
redisUrl: 'redis://api_node_cache:6379',
|
|
16
|
-
|
|
17
|
-
rabbitmqUrl: 'amqp://guest:guest@api_services_queuer:5672',
|
|
18
13
|
infrastructureHealthQueueName: 'infrastructure.health.checks',
|
|
14
|
+
infrastructureHealthPublishIntervalMs: 5000,
|
|
15
|
+
infrastructureHealthWaitMaxTimeMs: 300000,
|
|
16
|
+
infrastructureHealthWaitCheckIntervalMs: 5000,
|
|
17
|
+
infrastructureHealthTimeoutMs: 15000,
|
|
18
|
+
infrastructureHealthRedisTtlSeconds: 30,
|
|
19
|
+
infrastructureHealthCleanupIntervalMs: 10000,
|
|
20
|
+
|
|
21
|
+
infrastructureHealthQueueWaitMaxTimeMs: 60000,
|
|
22
|
+
infrastructureHealthQueueWaitCheckIntervalMs: 2000,
|
|
19
23
|
};
|
|
20
24
|
|
|
21
25
|
|
package/src/index.js
CHANGED
|
@@ -28,8 +28,6 @@ const {
|
|
|
28
28
|
optionalNumberEnv,
|
|
29
29
|
getCriticalConfig,
|
|
30
30
|
getCriticalConfigWithFallbacks,
|
|
31
|
-
getOptionalInfraConfig,
|
|
32
|
-
getServiceConfig,
|
|
33
31
|
getInfrastructureHealthConfig
|
|
34
32
|
} = require('./runtime-config');
|
|
35
33
|
|
|
@@ -53,9 +51,7 @@ module.exports = {
|
|
|
53
51
|
optionalEnv,
|
|
54
52
|
optionalNumberEnv,
|
|
55
53
|
getCriticalConfig,
|
|
56
|
-
getCriticalConfigWithFallbacks,
|
|
57
|
-
getOptionalInfraConfig,
|
|
58
|
-
getServiceConfig,
|
|
54
|
+
getCriticalConfigWithFallbacks,
|
|
59
55
|
getInfrastructureHealthConfig,
|
|
60
56
|
|
|
61
57
|
// Reporting utilities
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { connectRedis, buildRedisUrl } = require('../redisClient');
|
|
4
|
+
const runtimeCfg = require('../config');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* waitForHealthCheckQueueReady.js
|
|
@@ -33,11 +34,9 @@ const { connectRedis, buildRedisUrl } = require('../redisClient');
|
|
|
33
34
|
* @throws {Error} - If timeout is reached
|
|
34
35
|
*/
|
|
35
36
|
async function waitForHealthCheckQueueReady(options = {}) {
|
|
36
|
-
const redisUrl =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const maxWait = options.maxWait || parseInt(process.env.INFRASTRUCTURE_HEALTH_QUEUE_WAIT_MAX_TIME) || 60000; // 1 minute
|
|
40
|
-
const checkInterval = options.checkInterval || parseInt(process.env.INFRASTRUCTURE_HEALTH_QUEUE_WAIT_CHECK_INTERVAL) || 2000; // 2 seconds
|
|
37
|
+
const redisUrl = buildRedisUrl({ redisUrl: options.redisUrl });
|
|
38
|
+
const maxWait = runtimeCfg.get('infrastructureHealthQueueWaitMaxTimeMs', options.maxWait);
|
|
39
|
+
const checkInterval = runtimeCfg.get('infrastructureHealthQueueWaitCheckIntervalMs', options.checkInterval);
|
|
41
40
|
const logger = options.logger || console;
|
|
42
41
|
|
|
43
42
|
const log = (msg) => {
|
|
@@ -73,8 +72,7 @@ async function waitForHealthCheckQueueReady(options = {}) {
|
|
|
73
72
|
}
|
|
74
73
|
},
|
|
75
74
|
timeoutMs: 10000,
|
|
76
|
-
|
|
77
|
-
defaults: { host: 'api_node_cache', port: '6379' }
|
|
75
|
+
redisUrl
|
|
78
76
|
});
|
|
79
77
|
log('[HealthCheckQueueReady] Connected to Redis');
|
|
80
78
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { connectRedis, buildRedisUrl } = require('../redisClient');
|
|
4
|
+
const runtimeCfg = require('../config');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* waitForInfrastructureReady.js
|
|
@@ -44,11 +45,9 @@ const { connectRedis, buildRedisUrl } = require('../redisClient');
|
|
|
44
45
|
* Registry config (config.infrastructureHealth) is the source of truth for these defaults.
|
|
45
46
|
*/
|
|
46
47
|
async function waitForInfrastructureReady(options = {}) {
|
|
47
|
-
const redisUrl =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const maxWait = options.maxWait || parseInt(process.env.INFRASTRUCTURE_HEALTH_WAIT_MAX_TIME) || 300000; // 5 minutes
|
|
51
|
-
const checkInterval = options.checkInterval || parseInt(process.env.INFRASTRUCTURE_HEALTH_WAIT_CHECK_INTERVAL) || 5000; // 5 seconds
|
|
48
|
+
const redisUrl = buildRedisUrl({ redisUrl: options.redisUrl });
|
|
49
|
+
const maxWait = runtimeCfg.get('infrastructureHealthWaitMaxTimeMs', options.maxWait);
|
|
50
|
+
const checkInterval = runtimeCfg.get('infrastructureHealthWaitCheckIntervalMs', options.checkInterval);
|
|
52
51
|
const logger = options.logger || console;
|
|
53
52
|
|
|
54
53
|
// Helper to log messages (compatible with both console and winston)
|
|
@@ -90,8 +89,7 @@ async function waitForInfrastructureReady(options = {}) {
|
|
|
90
89
|
}
|
|
91
90
|
},
|
|
92
91
|
timeoutMs: 10000,
|
|
93
|
-
|
|
94
|
-
defaults: { host: 'api_node_cache', port: '6379' }
|
|
92
|
+
redisUrl
|
|
95
93
|
});
|
|
96
94
|
log('[InfrastructureReady] Connected to Redis');
|
|
97
95
|
|
package/src/redisClient.js
CHANGED
|
@@ -13,39 +13,38 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
const { createClient } = require('redis');
|
|
16
|
-
const
|
|
16
|
+
const runtimeCfg = require('./config');
|
|
17
|
+
const { createRuntimeConfig } = require('@onlineapps/runtime-config');
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Build a Redis connection URL from environment.
|
|
20
21
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* Environment variable precedence (checked in order):
|
|
25
|
-
* 1. REDIS_URL (full URL, e.g. redis://api_node_cache:6379) - ENV variable name
|
|
26
|
-
* 2. REDIS_HOST + REDIS_PORT (if REDIS_URL not set)
|
|
27
|
-
* 3. Fallback: redis://api_node_cache:6379 (docker-compose default)
|
|
22
|
+
* Strict rules:
|
|
23
|
+
* - No topology defaults (FAIL-FAST).
|
|
24
|
+
* - Priority: explicit redisUrl > env REDIS_URL.
|
|
28
25
|
*
|
|
29
26
|
* @param {Object} options - Options
|
|
30
|
-
* @param {Object} [options.env
|
|
31
|
-
* @param {
|
|
27
|
+
* @param {Object} [options.env] - Optional env override (tests/tools)
|
|
28
|
+
* @param {string} [options.redisUrl] - Explicit Redis URL override
|
|
32
29
|
* @returns {string} Redis connection URL
|
|
33
30
|
*/
|
|
34
31
|
function buildRedisUrl(options = {}) {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
const { env, redisUrl } = options;
|
|
33
|
+
|
|
34
|
+
if (env) {
|
|
35
|
+
const cfg = createRuntimeConfig({
|
|
36
|
+
defaults: {},
|
|
37
|
+
env,
|
|
38
|
+
schema: {
|
|
39
|
+
redisUrl: { env: 'REDIS_URL', required: true },
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
return cfg.get('redisUrl', redisUrl);
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
//
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
const port = env.REDIS_PORT || defaults.port || DEFAULTS.redisPort;
|
|
47
|
-
|
|
48
|
-
return `redis://${host}:${port}`;
|
|
45
|
+
// Default env source is the runtime-config resolver's env (process.env),
|
|
46
|
+
// but we never access process.env directly here.
|
|
47
|
+
return runtimeCfg.get('redisUrl', redisUrl);
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
/**
|
|
@@ -65,10 +64,10 @@ function createRedisClient(options = {}) {
|
|
|
65
64
|
forTests = false,
|
|
66
65
|
logger = console,
|
|
67
66
|
env,
|
|
68
|
-
|
|
67
|
+
redisUrl
|
|
69
68
|
} = options;
|
|
70
69
|
|
|
71
|
-
const url = buildRedisUrl({ env,
|
|
70
|
+
const url = buildRedisUrl({ env, redisUrl });
|
|
72
71
|
|
|
73
72
|
const socketOptions = forTests
|
|
74
73
|
? {
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const nodemailer = require('nodemailer');
|
|
4
|
+
const runtimeCfg = require('../config');
|
|
4
5
|
|
|
5
6
|
let transporter = null;
|
|
6
7
|
let cachedConfigSignature = null;
|
|
7
8
|
|
|
8
9
|
function loadConfig() {
|
|
9
10
|
return {
|
|
10
|
-
host:
|
|
11
|
-
port:
|
|
12
|
-
secure:
|
|
13
|
-
user:
|
|
14
|
-
pass:
|
|
15
|
-
from:
|
|
16
|
-
to:
|
|
11
|
+
host: runtimeCfg.get('infraReportSmtpHost'),
|
|
12
|
+
port: runtimeCfg.get('infraReportSmtpPort'),
|
|
13
|
+
secure: runtimeCfg.get('infraReportSmtpSecure'),
|
|
14
|
+
user: runtimeCfg.get('infraReportSmtpUser'),
|
|
15
|
+
pass: runtimeCfg.get('infraReportSmtpPass'),
|
|
16
|
+
from: runtimeCfg.get('infraReportFrom'),
|
|
17
|
+
to: runtimeCfg.get('infraReportTo')
|
|
17
18
|
};
|
|
18
19
|
}
|
|
19
20
|
|
package/src/runtime-config.js
CHANGED
|
@@ -2,35 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Runtime Configuration Helper
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* - Services don't silently connect to wrong infrastructure
|
|
11
|
-
* - Configuration problems are detected immediately
|
|
12
|
-
* - No hidden dependencies on hardcoded values
|
|
5
|
+
*
|
|
6
|
+
* Rules:
|
|
7
|
+
* - No inline process.env usage in implementation code (use runtime-config resolver).
|
|
8
|
+
* - No topology defaults (Redis/RabbitMQ URLs must be provided via explicit config or ENV).
|
|
9
|
+
* - Module-owned defaults are allowed only for non-topology behavior (intervals/timeouts).
|
|
13
10
|
*/
|
|
14
11
|
|
|
15
12
|
const runtimeCfg = require('./config');
|
|
13
|
+
const { createRuntimeConfig } = require('@onlineapps/runtime-config');
|
|
16
14
|
|
|
17
15
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* @param {string} description - Description for error message
|
|
21
|
-
* @returns {string} Environment variable value
|
|
22
|
-
* @throws {Error} If variable is not set
|
|
16
|
+
* Resolve arbitrary environment variables through runtime-config (no direct process.env access).
|
|
17
|
+
* Note: Prefer module schema keys (runtimeCfg.get) over these generic helpers.
|
|
23
18
|
*/
|
|
24
19
|
function requireEnv(name, description) {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
const cfg = createRuntimeConfig({
|
|
21
|
+
defaults: {},
|
|
22
|
+
schema: { value: { env: name, required: true } },
|
|
23
|
+
});
|
|
24
|
+
try {
|
|
25
|
+
return cfg.get('value');
|
|
26
|
+
} catch (err) {
|
|
27
|
+
const hint = description ? ` ${description}` : '';
|
|
28
|
+
throw new Error(`[ServiceConfig] Missing environment variable - ${name} is required.${hint}`.trim());
|
|
32
29
|
}
|
|
33
|
-
return value;
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
/**
|
|
@@ -41,11 +37,11 @@ function requireEnv(name, description) {
|
|
|
41
37
|
* @returns {any} Environment variable value or default
|
|
42
38
|
*/
|
|
43
39
|
function optionalEnv(name, defaultValue) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
return value;
|
|
40
|
+
const cfg = createRuntimeConfig({
|
|
41
|
+
defaults: {},
|
|
42
|
+
schema: { value: { env: name, default: defaultValue } },
|
|
43
|
+
});
|
|
44
|
+
return cfg.get('value');
|
|
49
45
|
}
|
|
50
46
|
|
|
51
47
|
/**
|
|
@@ -55,86 +51,36 @@ function optionalEnv(name, defaultValue) {
|
|
|
55
51
|
* @returns {number} Parsed number or default
|
|
56
52
|
*/
|
|
57
53
|
function optionalNumberEnv(name, defaultValue) {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return Number.isFinite(parsed) ? parsed : defaultValue;
|
|
54
|
+
const cfg = createRuntimeConfig({
|
|
55
|
+
defaults: {},
|
|
56
|
+
schema: { value: { env: name, default: defaultValue, type: 'number' } },
|
|
57
|
+
});
|
|
58
|
+
return cfg.get('value');
|
|
64
59
|
}
|
|
65
60
|
|
|
66
61
|
/**
|
|
67
62
|
* Get critical infrastructure configuration
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* This function requires ENV variables and fails fast (NO FALLBACKS).
|
|
71
|
-
*
|
|
63
|
+
*
|
|
64
|
+
* This function is FAIL-FAST (NO FALLBACKS).
|
|
72
65
|
* @returns {Object} Critical infrastructure config
|
|
73
66
|
* @throws {Error} If REDIS_URL or RABBITMQ_URL are not set
|
|
74
67
|
*/
|
|
75
68
|
function getCriticalConfig() {
|
|
76
69
|
return {
|
|
77
|
-
REDIS_URL:
|
|
78
|
-
RABBITMQ_URL:
|
|
70
|
+
REDIS_URL: runtimeCfg.get('redisUrl'),
|
|
71
|
+
RABBITMQ_URL: runtimeCfg.get('rabbitmqUrl'),
|
|
79
72
|
};
|
|
80
73
|
}
|
|
81
74
|
|
|
82
75
|
/**
|
|
83
76
|
* Get critical infrastructure configuration with fallbacks
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* Environment variables (checked in order):
|
|
89
|
-
* - REDIS_URL: Full Redis URL (e.g., redis://api_node_cache:6379)
|
|
90
|
-
* - RABBITMQ_URL: Full RabbitMQ URL (e.g., amqp://guest:guest@api_services_queuer:5672)
|
|
91
|
-
*
|
|
92
|
-
* Fallbacks (used only if ENV is not set):
|
|
93
|
-
* - Redis: redis://api_node_cache:6379 (docker-compose default)
|
|
94
|
-
* - RabbitMQ: amqp://guest:guest@api_services_queuer:5672 (docker-compose default)
|
|
95
|
-
*
|
|
77
|
+
*
|
|
78
|
+
* Strict mode: This function is kept for compatibility but DOES NOT provide fallbacks.
|
|
79
|
+
* Topology is FAIL-FAST (no defaults).
|
|
96
80
|
* @returns {Object} Critical infrastructure config with fallbacks
|
|
97
81
|
*/
|
|
98
82
|
function getCriticalConfigWithFallbacks() {
|
|
99
|
-
|
|
100
|
-
// Fallbacks are defined in ./defaults.js (module-owned)
|
|
101
|
-
return {
|
|
102
|
-
REDIS_URL: runtimeCfg.get('redisUrl'),
|
|
103
|
-
RABBITMQ_URL: runtimeCfg.get('rabbitmqUrl')
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Get optional infrastructure configuration
|
|
109
|
-
* These have sensible defaults for development
|
|
110
|
-
* @returns {Object} Optional infrastructure config
|
|
111
|
-
*/
|
|
112
|
-
function getOptionalInfraConfig() {
|
|
113
|
-
return {
|
|
114
|
-
POSTGRES_URL: optionalEnv('POSTGRES_URL', null), // Optional - only for services that need it
|
|
115
|
-
RABBITMQ_MGMT_URL: optionalEnv('RABBITMQ_MGMT_URL', null),
|
|
116
|
-
RABBITMQ_DEFAULT_USER: optionalEnv('RABBITMQ_DEFAULT_USER', 'guest'),
|
|
117
|
-
RABBITMQ_DEFAULT_PASS: optionalEnv('RABBITMQ_DEFAULT_PASS', 'guest'),
|
|
118
|
-
RABBITMQ_VHOST: optionalEnv('RABBITMQ_VHOST', '/')
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Get service configuration with defaults
|
|
124
|
-
* @param {Object} options - Options
|
|
125
|
-
* @param {string} [options.defaultPort] - Default port if PORT not set
|
|
126
|
-
* @param {string} [options.defaultLogLevel] - Default log level
|
|
127
|
-
* @returns {Object} Service config
|
|
128
|
-
*/
|
|
129
|
-
function getServiceConfig(options = {}) {
|
|
130
|
-
const { defaultPort = 3000, defaultLogLevel = 'info' } = options;
|
|
131
|
-
|
|
132
|
-
return {
|
|
133
|
-
PORT: optionalNumberEnv('PORT', defaultPort),
|
|
134
|
-
LOG_LEVEL: optionalEnv('LOG_LEVEL', defaultLogLevel),
|
|
135
|
-
SERVICE_NAME: optionalEnv('SERVICE_NAME', 'unknown-service'),
|
|
136
|
-
NODE_ENV: optionalEnv('NODE_ENV', 'development')
|
|
137
|
-
};
|
|
83
|
+
return getCriticalConfig();
|
|
138
84
|
}
|
|
139
85
|
|
|
140
86
|
/**
|
|
@@ -144,12 +90,14 @@ function getServiceConfig(options = {}) {
|
|
|
144
90
|
function getInfrastructureHealthConfig() {
|
|
145
91
|
return {
|
|
146
92
|
queueName: runtimeCfg.get('infrastructureHealthQueueName'),
|
|
147
|
-
publishInterval:
|
|
148
|
-
waitMaxTime:
|
|
149
|
-
waitCheckInterval:
|
|
150
|
-
healthCheckTimeout:
|
|
151
|
-
redisKeyTTL:
|
|
152
|
-
cleanupInterval:
|
|
93
|
+
publishInterval: runtimeCfg.get('infrastructureHealthPublishIntervalMs'),
|
|
94
|
+
waitMaxTime: runtimeCfg.get('infrastructureHealthWaitMaxTimeMs'),
|
|
95
|
+
waitCheckInterval: runtimeCfg.get('infrastructureHealthWaitCheckIntervalMs'),
|
|
96
|
+
healthCheckTimeout: runtimeCfg.get('infrastructureHealthTimeoutMs'),
|
|
97
|
+
redisKeyTTL: runtimeCfg.get('infrastructureHealthRedisTtlSeconds'),
|
|
98
|
+
cleanupInterval: runtimeCfg.get('infrastructureHealthCleanupIntervalMs'),
|
|
99
|
+
queueWaitMaxTime: runtimeCfg.get('infrastructureHealthQueueWaitMaxTimeMs'),
|
|
100
|
+
queueWaitCheckInterval: runtimeCfg.get('infrastructureHealthQueueWaitCheckIntervalMs'),
|
|
153
101
|
};
|
|
154
102
|
}
|
|
155
103
|
|
|
@@ -159,8 +107,6 @@ module.exports = {
|
|
|
159
107
|
optionalNumberEnv,
|
|
160
108
|
getCriticalConfig,
|
|
161
109
|
getCriticalConfigWithFallbacks,
|
|
162
|
-
getOptionalInfraConfig,
|
|
163
|
-
getServiceConfig,
|
|
164
110
|
getInfrastructureHealthConfig
|
|
165
111
|
};
|
|
166
112
|
|
|
@@ -6,20 +6,24 @@ const { buildRedisUrl } = require('../../src/redisClient');
|
|
|
6
6
|
|
|
7
7
|
describe('@onlineapps/service-common defaults @unit', () => {
|
|
8
8
|
test('should export stable module-owned defaults', () => {
|
|
9
|
-
expect(defaults.redisUrl).toBe('redis://api_node_cache:6379');
|
|
10
|
-
expect(defaults.rabbitmqUrl).toBe('amqp://guest:guest@api_services_queuer:5672');
|
|
11
9
|
expect(defaults.infrastructureHealthQueueName).toBe('infrastructure.health.checks');
|
|
10
|
+
expect(defaults.infrastructureHealthPublishIntervalMs).toBe(5000);
|
|
11
|
+
expect(defaults.infrastructureHealthWaitMaxTimeMs).toBe(300000);
|
|
12
|
+
expect(defaults.infrastructureHealthWaitCheckIntervalMs).toBe(5000);
|
|
13
|
+
expect(defaults.infrastructureHealthTimeoutMs).toBe(15000);
|
|
14
|
+
expect(defaults.infrastructureHealthRedisTtlSeconds).toBe(30);
|
|
15
|
+
expect(defaults.infrastructureHealthCleanupIntervalMs).toBe(10000);
|
|
16
|
+
expect(defaults.infrastructureHealthQueueWaitMaxTimeMs).toBe(60000);
|
|
17
|
+
expect(defaults.infrastructureHealthQueueWaitCheckIntervalMs).toBe(2000);
|
|
12
18
|
});
|
|
13
19
|
|
|
14
|
-
test('getCriticalConfigWithFallbacks should
|
|
20
|
+
test('getCriticalConfigWithFallbacks should fail-fast when env is missing (no topology defaults)', () => {
|
|
15
21
|
const oldRedis = process.env.REDIS_URL;
|
|
16
22
|
const oldRabbit = process.env.RABBITMQ_URL;
|
|
17
23
|
delete process.env.REDIS_URL;
|
|
18
24
|
delete process.env.RABBITMQ_URL;
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
expect(cfg.REDIS_URL).toBe(defaults.redisUrl);
|
|
22
|
-
expect(cfg.RABBITMQ_URL).toBe(defaults.rabbitmqUrl);
|
|
26
|
+
expect(() => getCriticalConfigWithFallbacks()).toThrow(/Missing required config/i);
|
|
23
27
|
|
|
24
28
|
if (oldRedis !== undefined) process.env.REDIS_URL = oldRedis;
|
|
25
29
|
if (oldRabbit !== undefined) process.env.RABBITMQ_URL = oldRabbit;
|
|
@@ -36,8 +40,7 @@ describe('@onlineapps/service-common defaults @unit', () => {
|
|
|
36
40
|
});
|
|
37
41
|
|
|
38
42
|
test('buildRedisUrl should fall back to module defaults host/port', () => {
|
|
39
|
-
|
|
40
|
-
expect(url).toBe(defaults.redisUrl);
|
|
43
|
+
expect(() => buildRedisUrl({ env: {}, defaults: {} })).toThrow(/Missing required config/i);
|
|
41
44
|
});
|
|
42
45
|
});
|
|
43
46
|
|
|
Binary file
|