samanbayaka 0.0.25 → 0.0.26
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 +39 -24
- package/commit-hash.mjs +1 -1
- package/config/nats.yml +1 -1
- package/helper/file/esm-loading.mjs +10 -83
- package/helper/mol-built-in/CustomLogger.mjs +13 -8
- package/helper/mol-built-in/HybridCacher.mjs +2 -2
- package/helper/utility/config-handler.mjs +7 -1
- package/helper/utility/error-handler.mjs +60 -46
- package/helper/utility/global-configs-validator.mjs +15 -5
- package/helper/utility/telemetry.mjs +2 -6
- package/index.mjs +189 -163
- package/package.json +1 -1
- package/services/gateway/index.mjs +9 -3
- package/services/kafkajs/index.mjs +3 -3
- package/services/system/index.mjs +87 -14
- package/services/system/scalar.mjs +0 -1
package/README.md
CHANGED
|
@@ -427,18 +427,30 @@ The `interMessageDelayMs` option introduces a delay between two consecutive mess
|
|
|
427
427
|
### Run the services
|
|
428
428
|
|
|
429
429
|
* development/testing
|
|
430
|
+
|
|
430
431
|
```bash
|
|
431
432
|
cd <your_path>/gateway
|
|
432
|
-
node index.mjs
|
|
433
|
+
SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' node index.mjs
|
|
433
434
|
cd <your_path>/hello
|
|
434
|
-
node index.mjs
|
|
435
|
+
SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' node index.mjs
|
|
435
436
|
```
|
|
437
|
+
or
|
|
438
|
+
```bash
|
|
439
|
+
pm2 stop "$(basename "$PWD")" && rm -rf node_modules/samanbayaka/ &&cp -r ../../samanbayaka/. node_modules/samanbayaka/ && SBK_CONFIG_CRED='sbk sbk@123 12379' pm2 start index.mjs --name "$(basename "$PWD")" --stop-exit-codes 1 --output /var/log/samanbayaka/sbk-out-${HOSTNAME}-$$.log --error /var/log/samanbayaka/sbk-err-${HOSTNAME}-$$.log
|
|
440
|
+
```
|
|
436
441
|
* production
|
|
437
442
|
```bash
|
|
438
443
|
cd <your_path>/gateway
|
|
439
|
-
node index.mjs >> /var/log/samanbayaka/sbk-${HOSTNAME}-$$.log 2>&1
|
|
444
|
+
SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' node index.mjs >> /var/log/samanbayaka/sbk-${HOSTNAME}-$$.log 2>&1
|
|
440
445
|
cd <your_path>/hello
|
|
441
|
-
node index.mjs >> /var/log/samanbayaka/sbk-${HOSTNAME}-$$.log 2>&1
|
|
446
|
+
SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' node index.mjs >> /var/log/samanbayaka/sbk-${HOSTNAME}-$$.log 2>&1
|
|
447
|
+
```
|
|
448
|
+
or
|
|
449
|
+
```bash
|
|
450
|
+
cd <your_path>/gateway
|
|
451
|
+
SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' pm2 start index.mjs --name "$(basename "$PWD")" --stop-exit-codes 1 --output /var/log/samanbayaka/sbk-out-${HOSTNAME}-$$.log --error /var/log/samanbayaka/sbk-err-${HOSTNAME}-$$.log
|
|
452
|
+
cd <your_path>/hello
|
|
453
|
+
SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' pm2 start index.mjs --name "$(basename "$PWD")" --stop-exit-codes 1 --output /var/log/samanbayaka/sbk-out-${HOSTNAME}-$$.log --error /var/log/samanbayaka/sbk-err-${HOSTNAME}-$$.log
|
|
442
454
|
```
|
|
443
455
|
|
|
444
456
|
## Demo
|
|
@@ -470,7 +482,7 @@ cd etcd
|
|
|
470
482
|
touch docker-compose.yml
|
|
471
483
|
export ETCD_ROOT_PW=<your_root_pass>
|
|
472
484
|
export ETCD_CONFIG_ADMIN_PW=<your_config_admin_pass>
|
|
473
|
-
mkdir -p /usr/local/etc/<your_project_name>
|
|
485
|
+
sudo mkdir -p /usr/local/etc/<your_project_name>
|
|
474
486
|
```
|
|
475
487
|
|
|
476
488
|
Open `docker-compose.yml` and paste the following:
|
|
@@ -561,6 +573,7 @@ services:
|
|
|
561
573
|
|
|
562
574
|
etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role add default
|
|
563
575
|
etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true default read /config/sbk/global/
|
|
576
|
+
etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true default read /config/sbk/members/
|
|
564
577
|
|
|
565
578
|
etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role add edge
|
|
566
579
|
etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true edge read /config/sbk/edge/
|
|
@@ -605,12 +618,19 @@ services:
|
|
|
605
618
|
etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role msg msg
|
|
606
619
|
|
|
607
620
|
# ---------------------------------------------------------
|
|
621
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/REVISION "" || true
|
|
622
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/APP_ENV development || true
|
|
623
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/LOG_LEVEL warn || true
|
|
624
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/MAX_L1_TTL 120 || true
|
|
625
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/MAX_L2_TTL 600 || true
|
|
626
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/TELEMETRY false || true
|
|
608
627
|
|
|
609
628
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/broker/yaml/nats "$(cat /etcd-data/nats.yml)" || true
|
|
610
629
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/catcher/yaml/redis "$(cat /etcd-data/redis.yml)" || true
|
|
611
630
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/telemetry/yaml/openobserve "$(cat /etcd-data/openobserve.yml)" || true
|
|
612
631
|
|
|
613
632
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/edge/yaml/auth "$(cat /etcd-data/auth.yml)" || true
|
|
633
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/edge/asset/path public || true
|
|
614
634
|
|
|
615
635
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/bridge/yaml/kafka "$(cat /etcd-data/kafka.yml)" || true
|
|
616
636
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/bridge/yaml/mqtt "$(cat /etcd-data/mqtt.yml)" || true
|
|
@@ -629,26 +649,21 @@ services:
|
|
|
629
649
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/dbs/pg/yaml/route-otp "$(cat /etcd-data/route-otp.yml)" || true
|
|
630
650
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/dbs/pg/yaml/outlook "$(cat /etcd-data/outlook.yml)" || true
|
|
631
651
|
|
|
632
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/
|
|
633
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/edge/port/sysapi 9876 || true
|
|
634
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/edge/asset/path public || true
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/APP_ENV development || true
|
|
638
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/LOG_LEVEL info || true
|
|
639
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/MAX_L1_TTL 120 || true
|
|
640
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/MAX_L2_TTL 600 || true
|
|
641
|
-
|
|
652
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/demo true || true
|
|
642
653
|
|
|
643
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/
|
|
644
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/
|
|
645
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/
|
|
646
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/
|
|
647
|
-
|
|
648
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/
|
|
649
|
-
|
|
650
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/
|
|
651
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/
|
|
654
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system true || true
|
|
655
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/PORT 8765 || true
|
|
656
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/BROADCAST_INTERVAL 600000 || true
|
|
657
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/LOG_LEVEL error || true
|
|
658
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/MAX_L1_TTL 0 || true
|
|
659
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/MAX_L2_TTL 0 || true
|
|
660
|
+
|
|
661
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/gateway true || true
|
|
662
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/gateway/envs/PORT 9876 || true
|
|
663
|
+
|
|
664
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/test true || true
|
|
665
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/sms add || true
|
|
666
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/email add || true
|
|
652
667
|
|
|
653
668
|
#etcdctl --endpoints=http://etcd:2379 --user=<your_user>:<your_pass> get /config/sbk/ --prefix
|
|
654
669
|
#etcdctl --endpoints=http://etcd:2379 --user=<your_user>:<your_pass> get /config/sbk/global/app_env
|
package/commit-hash.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const COMMIT_HASH = '
|
|
1
|
+
export const COMMIT_HASH = '2a7a879';
|
package/config/nats.yml
CHANGED
|
@@ -7,13 +7,17 @@ import os from "os"
|
|
|
7
7
|
import { createRequire } from 'module'
|
|
8
8
|
|
|
9
9
|
import chokidar from "chokidar"
|
|
10
|
-
import
|
|
11
|
-
import YAML from 'yaml'
|
|
10
|
+
import * as configHld from '#hUti/config-handler.mjs'
|
|
12
11
|
|
|
13
12
|
const __filename = fileURLToPath(import.meta.url)
|
|
14
13
|
const __dirname = path.dirname(__filename)
|
|
15
14
|
const require = createRequire(import.meta.url)
|
|
16
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Edge configs
|
|
18
|
+
*/
|
|
19
|
+
const EC_ASSET_PATH = (await configHld.getConfigs(`/config/sbk/edge/asset/path`)) || "public"
|
|
20
|
+
|
|
17
21
|
|
|
18
22
|
/**
|
|
19
23
|
* Configuration path
|
|
@@ -38,86 +42,9 @@ export const DEMO_SERVICES_DIR = path.join(ABSOLUTE_PATH, 'services', 'demo')
|
|
|
38
42
|
/**
|
|
39
43
|
* Feature services absolute path
|
|
40
44
|
*/
|
|
41
|
-
const SERVICES_DIR = __dirname
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* User credentials for accessing and reading configurations from
|
|
46
|
-
* the configuration server.
|
|
47
|
-
* @type {string}
|
|
48
|
-
*/
|
|
49
|
-
const [configUser, ConfigPass, configPort] = (process.env.SBK_CONFIG_CRED || "ur:pa:2379").split(":")
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Configuration Reader Client Options
|
|
54
|
-
* @type {object}
|
|
55
|
-
*/
|
|
56
|
-
const client = new Etcd3({
|
|
57
|
-
hosts: `http://etcd:${configPort}`,
|
|
58
|
-
auth: {
|
|
59
|
-
username: configUser,
|
|
60
|
-
password: ConfigPass
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Getting configurations through dynamic loading of ESM modules
|
|
67
|
-
* ftom the path defined in environment variable
|
|
68
|
-
* @param {string}
|
|
69
|
-
* @return {object}
|
|
70
|
-
*/
|
|
71
|
-
export const getConfig = async (path) => {
|
|
72
|
-
try {
|
|
73
|
-
const yamlText = await client.get(`/config${path}`)
|
|
74
|
-
if ( path.startsWith("/yaml/") ) {
|
|
75
|
-
return Object.freeze( YAML.parse(yamlText?.toString()) )
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
return yamlText?.toString()
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
} catch (err) {
|
|
82
|
-
throw new Error(`Unable to read configuration : ${err.message}`)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
export const watchConfig = async (path, callback) => {
|
|
88
|
-
const watcher = await client
|
|
89
|
-
.watch()
|
|
90
|
-
.prefix(`/config${path}`)
|
|
91
|
-
.create()
|
|
92
|
-
|
|
93
|
-
watcher.on("put", event => {
|
|
94
|
-
const evVal = path.startsWith("/yaml/")
|
|
95
|
-
? Object.freeze( YAML.parse(event.value.toString()) )
|
|
96
|
-
: event.value?.toString()
|
|
97
|
-
callback(
|
|
98
|
-
"put",
|
|
99
|
-
event.key?.toString(),
|
|
100
|
-
evVal
|
|
101
|
-
)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
watcher.on("delete", event => {
|
|
105
|
-
callback(
|
|
106
|
-
"delete",
|
|
107
|
-
event.key.toString(),
|
|
108
|
-
null
|
|
109
|
-
)
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Getting server configuration.
|
|
118
|
-
* @type {string}
|
|
119
|
-
*/
|
|
120
|
-
const CONFIG = {assetPath: "public"} // await getConfig('server')
|
|
45
|
+
const SERVICES_DIR = /node_modules/.test(__dirname)
|
|
46
|
+
? __dirname.split('node_modules')[0]
|
|
47
|
+
: __dirname.replace("/helper/file","")
|
|
121
48
|
|
|
122
49
|
|
|
123
50
|
/**
|
|
@@ -127,7 +54,7 @@ export const assetPath = {
|
|
|
127
54
|
rootFolder: path
|
|
128
55
|
.join(
|
|
129
56
|
ABSOLUTE_PATH,
|
|
130
|
-
|
|
57
|
+
EC_ASSET_PATH,
|
|
131
58
|
),
|
|
132
59
|
}
|
|
133
60
|
|
|
@@ -65,12 +65,17 @@ const pinoOptions = {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
export default {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
options:
|
|
68
|
+
export default (opts) => {
|
|
69
|
+
const { logger, logLevel } = opts
|
|
70
|
+
return logger == "CustomLogger"
|
|
71
|
+
? {
|
|
72
|
+
type: "Pino",
|
|
73
|
+
options: {
|
|
74
|
+
level: (logLevel || "info").toLowerCase(),
|
|
75
|
+
pino: {
|
|
76
|
+
options: pinoOptions
|
|
77
|
+
}
|
|
78
|
+
}
|
|
74
79
|
}
|
|
75
|
-
|
|
76
|
-
}
|
|
80
|
+
: "Console"
|
|
81
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Cachers } from "moleculer"
|
|
2
2
|
|
|
3
|
-
const MAX_L1_TTL =
|
|
4
|
-
const MAX_L2_TTL =
|
|
3
|
+
const MAX_L1_TTL = 600 // 10 minutes in seconds
|
|
4
|
+
const MAX_L2_TTL = 86400 // 24 hours in seconds
|
|
5
5
|
|
|
6
6
|
export default class HybridCacher extends Cachers.Base {
|
|
7
7
|
constructor(opts = {}) {
|
|
@@ -15,7 +15,7 @@ export const etcdCred = errHdl.validateConfigCred(process.env.SBK_CONFIG_CRED)
|
|
|
15
15
|
* Configuration Reader Client Options
|
|
16
16
|
* @type {object}
|
|
17
17
|
*/
|
|
18
|
-
const client = new Etcd3({
|
|
18
|
+
export const client = new Etcd3({
|
|
19
19
|
hosts: `http://etcd:${etcdCred[2]}`,
|
|
20
20
|
auth: {
|
|
21
21
|
username: etcdCred[0],
|
|
@@ -107,6 +107,7 @@ export const watchConfigs = async (path, callback) => {
|
|
|
107
107
|
null
|
|
108
108
|
)
|
|
109
109
|
})
|
|
110
|
+
return watcher
|
|
110
111
|
}
|
|
111
112
|
catch (err) {
|
|
112
113
|
throw new Error(`Unable to watck configuration: ${err.message}`)
|
|
@@ -114,3 +115,8 @@ export const watchConfigs = async (path, callback) => {
|
|
|
114
115
|
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
export const putConfig = async(path, data) => {
|
|
119
|
+
await client.put(path)
|
|
120
|
+
.value(data)
|
|
121
|
+
}
|
|
122
|
+
|
|
@@ -12,6 +12,7 @@ const configCredRegex = /^[a-zA-Z0-9]{3,16} [a-zA-Z0-9!@#$^_-]{3,16} [0-9]{4,5}$
|
|
|
12
12
|
const serviceNmRegx = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/
|
|
13
13
|
const portRegx = /^876[0-9]$/
|
|
14
14
|
const logLvlRegx = /^(fatal|error|warn|info|debug|trace)$/i
|
|
15
|
+
const telemetryRegx = /^(true|false)$/i
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -30,17 +31,16 @@ export const checkMinNoveVer = () => {
|
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
|
-
* Validate
|
|
34
|
+
* Validate APP_ENV entry
|
|
34
35
|
* @return {string}
|
|
35
36
|
*
|
|
36
37
|
* @throws error
|
|
37
38
|
*/
|
|
38
|
-
export const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
throw new Error(`NODE_ENV is '${env}', it must be 'development', 'production', or 'testing'`)
|
|
39
|
+
export const isValidAppEnv = (env) => {
|
|
40
|
+
if (!envRegx.test(env)) {
|
|
41
|
+
throw new Error(`APP_ENV is '${env}', it must be 'development', 'production', or 'testing'`)
|
|
42
42
|
}
|
|
43
|
-
return sysClassification[
|
|
43
|
+
return sysClassification[env]
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
|
|
@@ -62,8 +62,8 @@ export const isValidCommitHash = (hs) => {
|
|
|
62
62
|
* Validate namespace
|
|
63
63
|
* @retutn {string}
|
|
64
64
|
*/
|
|
65
|
-
export const validateNamespace = () => {
|
|
66
|
-
return `${
|
|
65
|
+
export const validateNamespace = (env) => {
|
|
66
|
+
return `${isValidAppEnv(env)}-sbk-${isValidCommitHash(COMMIT_HASH)}`.toUpperCase()
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
|
|
@@ -74,29 +74,23 @@ export const validateNamespace = () => {
|
|
|
74
74
|
* @throws error
|
|
75
75
|
*/
|
|
76
76
|
export const validateConfigCred = (env) => {
|
|
77
|
-
// const env = process.env.SBK_CONFIG_CRED
|
|
78
77
|
if(!configCredRegex.test(env)){
|
|
79
|
-
throw new Error(`SBK_CONFIG_CRED is "${env}". It must be a valid Etcd user credential in the format "user password port".`)
|
|
78
|
+
throw new Error(`Environment variable SBK_CONFIG_CRED is "${env}". It must be a valid Etcd user credential in the format "user password port".`)
|
|
80
79
|
}
|
|
81
80
|
return env.split(" ")
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
|
|
85
84
|
/**
|
|
86
|
-
* Validate that the
|
|
85
|
+
* Validate that the MAX_L1_TTL is defined and does not exceed 120 seconds
|
|
87
86
|
* @return {number} between 0 to 120
|
|
88
87
|
*
|
|
89
88
|
* @throws error
|
|
90
89
|
*/
|
|
91
|
-
export const validateL1TTL = () => {
|
|
92
|
-
const ttl = process.env.MAX_L1_TTL
|
|
93
|
-
|
|
94
|
-
if (ttl === undefined) return 120
|
|
95
|
-
|
|
90
|
+
export const validateL1TTL = (ttl = 120) => {
|
|
96
91
|
const num = Number(ttl)
|
|
97
|
-
|
|
98
92
|
if (!Number.isInteger(num) || num < 0 || num > 120) {
|
|
99
|
-
throw new Error(`
|
|
93
|
+
throw new Error(`Configuration variable 'MAX_L1_TTL' is ${ttl}, it must be between 0 and 120`)
|
|
100
94
|
}
|
|
101
95
|
|
|
102
96
|
return num
|
|
@@ -104,20 +98,15 @@ export const validateL1TTL = () => {
|
|
|
104
98
|
|
|
105
99
|
|
|
106
100
|
/**
|
|
107
|
-
* Validate that the
|
|
101
|
+
* Validate that the MAX_L2_TTL is defined and does not exceed 600 seconds
|
|
108
102
|
* @return {number} between 0 to 600
|
|
109
103
|
*
|
|
110
104
|
* @throws error
|
|
111
105
|
*/
|
|
112
|
-
export const validateL2TTL = () => {
|
|
113
|
-
const ttl = process.env.MAX_L2_TTL
|
|
114
|
-
|
|
115
|
-
if (ttl === undefined) return 600
|
|
116
|
-
|
|
106
|
+
export const validateL2TTL = (ttl = 600) => {
|
|
117
107
|
const num = Number(ttl)
|
|
118
|
-
|
|
119
108
|
if (!Number.isInteger(num) || num < 0 || num > 600) {
|
|
120
|
-
throw new Error(`
|
|
109
|
+
throw new Error(`Configuration variable 'MAX_L2_TTL' is ${ttl}, it must be between 0 and 600`)
|
|
121
110
|
}
|
|
122
111
|
|
|
123
112
|
return num
|
|
@@ -125,16 +114,16 @@ export const validateL2TTL = () => {
|
|
|
125
114
|
|
|
126
115
|
|
|
127
116
|
/**
|
|
128
|
-
* Validate
|
|
117
|
+
* Validate configuration variable SBK_PORT for Apigateway port number
|
|
129
118
|
* @return {number} between 8760 to 8769
|
|
130
119
|
*
|
|
131
120
|
* @throws error
|
|
132
121
|
*/
|
|
133
|
-
export const validatePort = () => {
|
|
134
|
-
if (
|
|
135
|
-
throw new Error(`
|
|
122
|
+
export const validatePort = (port) => {
|
|
123
|
+
if ( port !== undefined && !(portRegx.test(port)) ) {
|
|
124
|
+
throw new Error(`Configuration variable 'PORT' is ${port}, it must be between 8760 and 8769`)
|
|
136
125
|
}
|
|
137
|
-
return Number(
|
|
126
|
+
return Number(port || 8765)
|
|
138
127
|
}
|
|
139
128
|
|
|
140
129
|
|
|
@@ -146,7 +135,7 @@ export const validatePort = () => {
|
|
|
146
135
|
*/
|
|
147
136
|
export const validateLogLevel = (env) => {
|
|
148
137
|
if ( !(logLvlRegx.test(env)) ) {
|
|
149
|
-
throw new Error(`
|
|
138
|
+
throw new Error(`LOG_LEVEL is ${env}, it must be fatal | error | warn | info | debug | trace `)
|
|
150
139
|
}
|
|
151
140
|
return env
|
|
152
141
|
}
|
|
@@ -202,22 +191,47 @@ export const validateServiceName = (schema, pkgName) => {
|
|
|
202
191
|
|
|
203
192
|
|
|
204
193
|
/**
|
|
205
|
-
*
|
|
194
|
+
* Telemetry enable or disable inputs
|
|
195
|
+
* @param {string}
|
|
196
|
+
* @return {boolean}
|
|
206
197
|
*/
|
|
207
|
-
export const
|
|
208
|
-
if(
|
|
209
|
-
|
|
198
|
+
export const validateTelemetry = (env) => {
|
|
199
|
+
if ( !(telemetryRegx.test(env)) ) {
|
|
200
|
+
throw new Error(`TELEMETRY is ${env}, it must be true | false `)
|
|
210
201
|
}
|
|
202
|
+
return env.toLowerCase() === "true" ? true : false
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Validate config revision
|
|
207
|
+
* @param {string}
|
|
208
|
+
* @return {object}
|
|
209
|
+
*/
|
|
210
|
+
export const validateConfRevision = (env) => {
|
|
211
|
+
env = env || '{"pub":0,"edg":0,"mem":{"system":0,"gateway":0}}'
|
|
212
|
+
return JSON.parse(env)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Graceful shutdown handler
|
|
218
|
+
*/
|
|
219
|
+
export const gracefulShutdown = async (broker, signal, err=null) => {
|
|
211
220
|
|
|
212
|
-
broker.logger.info({message:
|
|
213
|
-
|
|
221
|
+
broker.logger.info({message: `${signal} detected, Stopping the broker...`})
|
|
214
222
|
try {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
223
|
+
if(err) {
|
|
224
|
+
await broker.stop()
|
|
225
|
+
broker.logger.error({message: `Broker stopped after detecting the ${signal} signal.`}, {err})
|
|
226
|
+
process.exit(1)
|
|
227
|
+
}
|
|
228
|
+
else{
|
|
229
|
+
await broker.stop()
|
|
230
|
+
broker.logger.info({message: "Broker stopped gracefully."})
|
|
231
|
+
process.exit(0)
|
|
232
|
+
}
|
|
233
|
+
} catch (brokerStoppingErr) {
|
|
234
|
+
broker.logger.error({brokerStoppingErr}, "Unable to stop the broker.")
|
|
221
235
|
process.exit(1)
|
|
222
236
|
}
|
|
223
237
|
}
|
|
@@ -229,7 +243,7 @@ export const shutdownHdl = async (broker, signal, err=null) => {
|
|
|
229
243
|
*
|
|
230
244
|
* @type {Object}
|
|
231
245
|
*/
|
|
232
|
-
export const
|
|
246
|
+
export const ErrorFormatterMW = {
|
|
233
247
|
localAction: (next) => {
|
|
234
248
|
return async(ctx) => {
|
|
235
249
|
try {
|
|
@@ -287,7 +301,7 @@ export const SbkErrorMiddleware = {
|
|
|
287
301
|
* Ensures all errors include a standard set of fields such as status code,
|
|
288
302
|
* message, and optional metadata for client consumption.
|
|
289
303
|
*/
|
|
290
|
-
export const
|
|
304
|
+
export const httpErrorFormatter = (req, res, err)=>{
|
|
291
305
|
const code = err.code || 500
|
|
292
306
|
const errorBody = {
|
|
293
307
|
...(err?.data || { message: err.message }),
|
|
@@ -4,14 +4,24 @@ export const validateGlobalConfigs = async(prefix) => {
|
|
|
4
4
|
try{
|
|
5
5
|
const nodeVer = errHdl.checkMinNoveVer()
|
|
6
6
|
const configHdl = await import("./config-handler.mjs")
|
|
7
|
+
const { serviceDtls } = await import("#hFil/esm-loading.mjs")
|
|
7
8
|
const globalConfigs = await configHdl.getConfigAll(prefix)
|
|
8
9
|
|
|
10
|
+
|
|
11
|
+
const isServiceRemoved = (((await configHdl.getConfigs( `/config/sbk/members/${serviceDtls.name}` )) || "false") == "false")
|
|
12
|
+
if ( serviceDtls.name != "samanbayaka" && isServiceRemoved ) {
|
|
13
|
+
throw new Error (`The service "${serviceDtls.name}" is not in the trusted list. Please contact your CONFIGADMIN for assistance.`)
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
return Object.freeze({
|
|
10
17
|
nodeVer,
|
|
11
18
|
configCred: configHdl.etcdCred,
|
|
12
|
-
maxL1TTL: errHdl.validateL1TTL(),
|
|
13
|
-
maxL2TTL: errHdl.validateL2TTL(),
|
|
14
|
-
logLevel: errHdl.validateLogLevel(globalConfigs
|
|
19
|
+
maxL1TTL: errHdl.validateL1TTL(globalConfigs?.MAX_L1_TTL),
|
|
20
|
+
maxL2TTL: errHdl.validateL2TTL(globalConfigs?.MAX_L2_TTL),
|
|
21
|
+
logLevel: errHdl.validateLogLevel(globalConfigs?.LOG_LEVEL),
|
|
22
|
+
telemetry: errHdl.validateTelemetry(globalConfigs?.TELEMETRY),
|
|
23
|
+
configRevision: errHdl.validateConfRevision(globalConfigs?.REVISION),
|
|
24
|
+
serviceDtls,
|
|
15
25
|
hostEntry: {
|
|
16
26
|
nats: await errHdl.validateHostEntry('nats'),
|
|
17
27
|
redis: await errHdl.validateHostEntry('redis'),
|
|
@@ -19,7 +29,7 @@ export const validateGlobalConfigs = async(prefix) => {
|
|
|
19
29
|
redpanda: await errHdl.validateHostEntry('redpanda', true),
|
|
20
30
|
openobserve: await errHdl.validateHostEntry('openobserve', true),
|
|
21
31
|
},
|
|
22
|
-
namespaceTxt: errHdl.validateNamespace(),
|
|
32
|
+
namespaceTxt: errHdl.validateNamespace(globalConfigs.APP_ENV),
|
|
23
33
|
})
|
|
24
34
|
}
|
|
25
35
|
catch(err){
|
|
@@ -32,4 +42,4 @@ export const validateGlobalConfigs = async(prefix) => {
|
|
|
32
42
|
/**
|
|
33
43
|
* Validate the Samanbayaka global configurations
|
|
34
44
|
*/
|
|
35
|
-
export const SBK_GLOBAL_CONFIGS = await validateGlobalConfigs("/config/sbk/global/envs/")
|
|
45
|
+
export const SBK_GLOBAL_CONFIGS = await validateGlobalConfigs("/config/sbk/global/envs/")
|
|
@@ -22,7 +22,7 @@ const resource = resourceFromAttributes({
|
|
|
22
22
|
// })
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
export const
|
|
25
|
+
export const createOpenTelemetryExporters = (config) => {
|
|
26
26
|
const sdk = new NodeSDK({
|
|
27
27
|
resource,
|
|
28
28
|
|
|
@@ -52,11 +52,9 @@ export const createSdk = (config) => {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
55
|
const tracer = trace.getTracer("moleculer")
|
|
58
56
|
|
|
59
|
-
export const
|
|
57
|
+
export const OpenTelemetryMW = (isEnabled) => {
|
|
60
58
|
const meter = metrics.getMeter("moleculer")
|
|
61
59
|
|
|
62
60
|
const requestCounter = meter.createCounter("moleculer_requests_total", {
|
|
@@ -73,8 +71,6 @@ export const OpenTelemetry = () => {
|
|
|
73
71
|
name: "otel",
|
|
74
72
|
|
|
75
73
|
localAction(next, action) {
|
|
76
|
-
const isEnabled = process.env.SBK_TELEMETRY_ENABLE?.toLowerCase() === "true"
|
|
77
|
-
|
|
78
74
|
if ( !isEnabled ) return next
|
|
79
75
|
return async (ctx) => {
|
|
80
76
|
const startTime = Date.now()
|
package/index.mjs
CHANGED
|
@@ -2,104 +2,185 @@
|
|
|
2
2
|
import { ServiceBroker, Errors } from "moleculer"
|
|
3
3
|
|
|
4
4
|
import {SBK_GLOBAL_CONFIGS} from '#hUti/global-configs-validator.mjs'
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
validateServiceName,
|
|
8
|
-
SbkErrorMiddleware,
|
|
9
|
-
} from '#hUti/error-handler.mjs'
|
|
10
|
-
|
|
11
|
-
import * as configHld from '#hUti/config-handler.mjs'
|
|
12
|
-
|
|
13
|
-
import { createSdk, OpenTelemetry } from '#hUti/telemetry.mjs'
|
|
14
|
-
import {
|
|
15
|
-
serviceDtls,
|
|
16
|
-
getConfig,
|
|
17
|
-
watchConfig,
|
|
18
|
-
DEMO_SERVICES_DIR
|
|
19
|
-
} from '#hFil/esm-loading.mjs'
|
|
5
|
+
import * as configHdl from '#hUti/config-handler.mjs'
|
|
6
|
+
|
|
20
7
|
import AjvValidator from "#hMol/AjvValidator.mjs"
|
|
21
|
-
import
|
|
8
|
+
import CustomLogger from "#hMol/CustomLogger.mjs"
|
|
22
9
|
import HybridCacher from "#hMol/HybridCacher.mjs"
|
|
23
|
-
import about from '#sAbt/index.mjs'
|
|
24
|
-
import apiGateway from '#sApi/index.mjs'
|
|
25
|
-
import sysApi from '#sSys/index.mjs'
|
|
26
|
-
import { auxBrokerParamsValidator } from '#hUti/aux-broker-params-validator.mjs'
|
|
27
|
-
import * as demo from '#sDmo/index.mjs'
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const BROKER_CONFIG = await configHld.getConfigs('/config/sbk/global/broker/yaml/nats')
|
|
31
|
-
const CATCHER_CONFIG = await configHld.getConfigs('/config/sbk/global/catcher/yaml/redis')
|
|
32
|
-
const TELEMETRY_CONFIG = await configHld.getConfigs('/config/sbk/global/telemetry/yaml/openobserve')
|
|
33
|
-
|
|
34
|
-
const sbkLoggers = {
|
|
35
|
-
"CustomPino": customLogger
|
|
36
|
-
}
|
|
37
10
|
|
|
11
|
+
import { gracefulShutdown, validateServiceName, ErrorFormatterMW } from '#hUti/error-handler.mjs'
|
|
12
|
+
import { createOpenTelemetryExporters, OpenTelemetryMW } from '#hUti/telemetry.mjs'
|
|
38
13
|
|
|
39
14
|
/**
|
|
40
|
-
*
|
|
41
|
-
* @type {Boolean}
|
|
15
|
+
* Global Configs
|
|
42
16
|
*/
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
) || false
|
|
17
|
+
const BROKER_CONFIG = await configHdl.getConfigs('/config/sbk/global/broker/yaml/nats')
|
|
18
|
+
const CATCHER_CONFIG = await configHdl.getConfigs('/config/sbk/global/catcher/yaml/redis')
|
|
19
|
+
const TELEMETRY_CONFIG = await configHdl.getConfigs('/config/sbk/global/telemetry/yaml/openobserve')
|
|
47
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Local configs
|
|
23
|
+
*/
|
|
24
|
+
const LC_LOG_LEVEL = await configHdl.getConfigs(`/config/sbk/members/${SBK_GLOBAL_CONFIGS.serviceDtls.name}/envs/LOG_LEVEL`)
|
|
25
|
+
const LC_TELEMETRY = await configHdl.getConfigs(`/config/sbk/members/${SBK_GLOBAL_CONFIGS.serviceDtls.name}/envs/TELEMETRY`)
|
|
26
|
+
const LC_MAX_L1_TTL = await configHdl.getConfigs(`/config/sbk/members/${SBK_GLOBAL_CONFIGS.serviceDtls.name}/envs/MAX_L1_TTL`)
|
|
27
|
+
const LC_MAX_L2_TTL = await configHdl.getConfigs(`/config/sbk/members/${SBK_GLOBAL_CONFIGS.serviceDtls.name}/envs/MAX_L2_TTL`)
|
|
48
28
|
|
|
49
29
|
/**
|
|
50
|
-
*
|
|
30
|
+
* Service Broker initialization params with default values
|
|
51
31
|
*/
|
|
52
|
-
const
|
|
32
|
+
const LOG_LEVEL = LC_LOG_LEVEL || SBK_GLOBAL_CONFIGS.logLevel || "debug"
|
|
33
|
+
const TELEMETRY = LC_TELEMETRY || SBK_GLOBAL_CONFIGS.telemetry || true
|
|
34
|
+
const MAX_L1_TTL = LC_MAX_L1_TTL || SBK_GLOBAL_CONFIGS.maxL1TTL || 120
|
|
35
|
+
const MAX_L2_TTL = LC_MAX_L2_TTL || SBK_GLOBAL_CONFIGS.maxL2TTL || 600
|
|
53
36
|
|
|
54
37
|
|
|
38
|
+
const createSbkServices = async(schemas, isREPL = false) => {
|
|
55
39
|
|
|
56
|
-
/**
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const brokerInit = (brokerConfig) => {
|
|
61
|
-
return new ServiceBroker({
|
|
62
|
-
...brokerConfig,
|
|
63
|
-
...{
|
|
64
|
-
namespace: SBK_GLOBAL_CONFIGS.namespaceTxt,
|
|
65
|
-
nodeID: serviceDtls.id,
|
|
66
|
-
validator: new AjvValidator(),
|
|
67
|
-
logger: sbkLoggers[brokerConfig.logger] || "Console",
|
|
68
|
-
cacher: new HybridCacher(CATCHER_CONFIG),
|
|
69
|
-
},
|
|
70
|
-
middlewares: [SbkErrorMiddleware, OpenTelemetry],
|
|
71
|
-
})
|
|
72
|
-
}
|
|
40
|
+
/**
|
|
41
|
+
* Initialize OTLP metrics and telemetry exporter
|
|
42
|
+
*/
|
|
43
|
+
const sdk = await createOpenTelemetryExporters(TELEMETRY_CONFIG)
|
|
73
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Moleculer srvice broker configurations
|
|
47
|
+
* @type {ServiceBroker}
|
|
48
|
+
*/
|
|
49
|
+
const broker = new ServiceBroker({
|
|
50
|
+
...BROKER_CONFIG,
|
|
51
|
+
...{
|
|
52
|
+
namespace: SBK_GLOBAL_CONFIGS.namespaceTxt,
|
|
53
|
+
nodeID: SBK_GLOBAL_CONFIGS.serviceDtls.id,
|
|
54
|
+
validator: new AjvValidator(),
|
|
55
|
+
logLevel: LOG_LEVEL,
|
|
56
|
+
logger: CustomLogger({
|
|
57
|
+
logger: BROKER_CONFIG.logger,
|
|
58
|
+
logLevel: LOG_LEVEL
|
|
59
|
+
}),
|
|
60
|
+
cacher: new HybridCacher({
|
|
61
|
+
...CATCHER_CONFIG,
|
|
62
|
+
...{
|
|
63
|
+
ttl: [MAX_L2_TTL, MAX_L1_TTL]
|
|
64
|
+
}
|
|
65
|
+
}),
|
|
66
|
+
},
|
|
67
|
+
middlewares: [ErrorFormatterMW, OpenTelemetryMW(TELEMETRY)],
|
|
68
|
+
})
|
|
74
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Creating moleculer services
|
|
72
|
+
*/
|
|
73
|
+
schemas = Array.isArray(schemas) ? schemas : [schemas]
|
|
74
|
+
for ( const [index, schema] of schemas.entries() ) {
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Listner for configuration revision
|
|
78
|
+
* @type {Object}
|
|
79
|
+
*/
|
|
80
|
+
const configRevisionListner = {
|
|
81
|
+
"config.revisions": (ctx) => {
|
|
82
|
+
setImmediate(async () => {
|
|
83
|
+
ctx.broker.logger.debug({message: "Config revision received"}, ctx.params)
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Restart the service when the global configuration is updated
|
|
87
|
+
*/
|
|
88
|
+
if( SBK_GLOBAL_CONFIGS.configRevision.pub != ctx.params.pub ){
|
|
89
|
+
ctx.broker.logger.warn(`Global configuration deployed by CONFIGADMIN and the service "${SBK_GLOBAL_CONFIGS.serviceDtls.name}" is restarting in progress...`)
|
|
90
|
+
await ctx.broker.stop()
|
|
91
|
+
process.exit(0)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Restart the service if it is an edge service in response to an edge configuration update
|
|
96
|
+
*/
|
|
97
|
+
if(
|
|
98
|
+
SBK_GLOBAL_CONFIGS.configRevision.edg != ctx.params.edg
|
|
99
|
+
&& schema?.settings?.port != undefined
|
|
100
|
+
){
|
|
101
|
+
ctx.broker.logger.warn(`Edge configuration deployed by CONFIGADMIN and the service "${SBK_GLOBAL_CONFIGS.serviceDtls.name}" is restarting in progress...`)
|
|
102
|
+
await ctx.broker.stop()
|
|
103
|
+
process.exit(0)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Restart the service when the corresponding configuration is updated
|
|
108
|
+
*/
|
|
109
|
+
if(
|
|
110
|
+
SBK_GLOBAL_CONFIGS.configRevision.mem[SBK_GLOBAL_CONFIGS.serviceDtls.name] != ctx.params.mem[SBK_GLOBAL_CONFIGS.serviceDtls.name]
|
|
111
|
+
&& ctx.params.mem[SBK_GLOBAL_CONFIGS.serviceDtls.name] >= 0
|
|
112
|
+
){
|
|
113
|
+
ctx.broker.logger.warn(`Configuration deployed by CONFIGADMIN and the service "${SBK_GLOBAL_CONFIGS.serviceDtls.name}" is restarting in progress...`)
|
|
114
|
+
await ctx.broker.stop()
|
|
115
|
+
process.exit(0)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Stop the service when CONFIGADMIN removes it from the trusted list
|
|
120
|
+
*/
|
|
121
|
+
if( ctx.params.mem[SBK_GLOBAL_CONFIGS.serviceDtls.name] < 0 ){
|
|
122
|
+
ctx.broker.logger.error(`The service "${SBK_GLOBAL_CONFIGS.serviceDtls.name}" was stopped by CONFIGADMIN.`)
|
|
123
|
+
await ctx.broker.stop()
|
|
124
|
+
process.exit(1)
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
}
|
|
76
128
|
|
|
77
|
-
|
|
129
|
+
}
|
|
78
130
|
|
|
131
|
+
/**
|
|
132
|
+
* merge configuration listner with user defined events
|
|
133
|
+
* @type {Object}
|
|
134
|
+
*/
|
|
135
|
+
schema.events = {
|
|
136
|
+
...schema?.events,
|
|
137
|
+
...configRevisionListner
|
|
138
|
+
}
|
|
79
139
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
process.on("beforeExit", async () => {
|
|
84
|
-
await sdk.shutdown()
|
|
85
|
-
})
|
|
86
|
-
process.on("SIGINT", (signal) => {
|
|
87
|
-
shutdownHdl(broker, signal)
|
|
88
|
-
}) // Ctrl+C
|
|
89
|
-
process.on("SIGTERM", (signal) => {
|
|
90
|
-
shutdownHdl(broker, signal)
|
|
91
|
-
}) // kill command
|
|
140
|
+
if( index == 0 ) validateServiceName(schema, SBK_GLOBAL_CONFIGS.serviceDtls.name)
|
|
141
|
+
broker.createService(schema)
|
|
142
|
+
}
|
|
92
143
|
|
|
93
144
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
145
|
+
if(isREPL){
|
|
146
|
+
/**
|
|
147
|
+
* Start broker with repl mode
|
|
148
|
+
*/
|
|
149
|
+
broker.start().then(() => broker.repl())
|
|
150
|
+
}
|
|
151
|
+
else{
|
|
152
|
+
/**
|
|
153
|
+
* Start services
|
|
154
|
+
*/
|
|
155
|
+
broker.start()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Listen for force stop signals
|
|
161
|
+
*/
|
|
162
|
+
process.on("beforeExit", async () => {
|
|
163
|
+
await configHdl.client.close()
|
|
164
|
+
await sdk.shutdown()
|
|
165
|
+
})
|
|
166
|
+
process.on("SIGINT", (signal) => {
|
|
167
|
+
gracefulShutdown(broker, signal)
|
|
168
|
+
}) // Ctrl+C
|
|
169
|
+
process.on("SIGTERM", (signal) => {
|
|
170
|
+
gracefulShutdown(broker, signal)
|
|
171
|
+
}) // kill command
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Optional: handle uncaught errors
|
|
176
|
+
*/
|
|
177
|
+
process.on("uncaughtException", (err) => {
|
|
178
|
+
gracefulShutdown(broker, "Uncaught Exception", err)
|
|
179
|
+
})
|
|
180
|
+
process.on("unhandledRejection", (err) => {
|
|
181
|
+
gracefulShutdown(broker, "Unhandled Rejection", err)
|
|
182
|
+
})
|
|
183
|
+
}
|
|
103
184
|
|
|
104
185
|
|
|
105
186
|
/**
|
|
@@ -107,26 +188,32 @@ process.on("unhandledRejection", (err) => {
|
|
|
107
188
|
*/
|
|
108
189
|
export default {
|
|
109
190
|
Errors,
|
|
110
|
-
|
|
191
|
+
getConfigs: configHdl.getConfigs,
|
|
111
192
|
|
|
112
193
|
/**
|
|
113
194
|
* Loading Demo
|
|
114
195
|
*/
|
|
115
196
|
createDemo: async() => {
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
broker.createService(gtWy)
|
|
120
|
-
broker.createService(demo.user)
|
|
121
|
-
broker.createService(demo.role)
|
|
122
|
-
broker.createService(demo.mail)
|
|
123
|
-
broker.createService(demo.sms)
|
|
197
|
+
const { default: about } = await import('#sAbt/index.mjs')
|
|
198
|
+
const { default: apiGateway } = await import('#sApi/index.mjs')
|
|
199
|
+
const demo = await import('#sDmo/index.mjs')
|
|
124
200
|
|
|
201
|
+
const gtWy = {...apiGateway}
|
|
202
|
+
gtWy.name = "demo"
|
|
203
|
+
gtWy.settings.port = 3000
|
|
204
|
+
gtWy.settings.routes = gtWy.settings.routes.map((rt) => {
|
|
205
|
+
rt.path = `/demo${rt.path}`
|
|
206
|
+
return rt
|
|
207
|
+
})
|
|
208
|
+
createSbkServices([
|
|
209
|
+
gtWy,
|
|
210
|
+
about,
|
|
211
|
+
demo.user,
|
|
212
|
+
demo.role,
|
|
213
|
+
demo.mail,
|
|
214
|
+
demo.sms
|
|
215
|
+
], true)
|
|
125
216
|
|
|
126
|
-
/**
|
|
127
|
-
* Start broker with repl mode
|
|
128
|
-
*/
|
|
129
|
-
broker.start().then(() => broker.repl())
|
|
130
217
|
},
|
|
131
218
|
|
|
132
219
|
/**
|
|
@@ -134,80 +221,27 @@ export default {
|
|
|
134
221
|
* @return {void}
|
|
135
222
|
*/
|
|
136
223
|
registerSystemAPI: async () => {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Start broker
|
|
142
|
-
*/
|
|
143
|
-
broker.start()
|
|
224
|
+
const { default: sysApi } = await import('#sSys/index.mjs')
|
|
225
|
+
createSbkServices(sysApi)
|
|
226
|
+
|
|
144
227
|
},
|
|
145
228
|
|
|
146
229
|
registerEdgeAPI: async () => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Start broker
|
|
153
|
-
*/
|
|
154
|
-
broker.start()
|
|
230
|
+
const { default: about } = await import('#sAbt/index.mjs')
|
|
231
|
+
const { default: apiGateway } = await import('#sApi/index.mjs')
|
|
232
|
+
createSbkServices([apiGateway, about])
|
|
155
233
|
|
|
156
234
|
},
|
|
157
235
|
|
|
158
236
|
|
|
159
237
|
registerServices: async (schema) => {
|
|
160
|
-
|
|
161
|
-
validateServiceName(schema, serviceDtls.name)
|
|
162
|
-
const whitelistedServices = await configHld.getConfigKeys( `/config/sbk/global/members/${serviceDtls.name}` )
|
|
163
|
-
|
|
164
|
-
if ( !whitelistedServices.includes( serviceDtls.name ) ) {
|
|
165
|
-
throw new Error (`The service "${serviceDtls.name}" is not whitelisted. Please contact your system administrator for assistance.`)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Create moleculer service from schema object
|
|
170
|
-
*/
|
|
171
|
-
broker.createService(schema)
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Start broker
|
|
175
|
-
*/
|
|
176
|
-
broker.start()
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Restart service on configuration change
|
|
180
|
-
* @param {string} config path like '/yaml/nats'
|
|
181
|
-
* @param {function} async callback function
|
|
182
|
-
* @return {void}
|
|
183
|
-
*/
|
|
184
|
-
configHld.watchConfigs('/config/sbk/global/broker/yaml/nats', async (ev, key, val) => {
|
|
185
|
-
broker.stop()
|
|
186
|
-
broker.logger.warn(`New configuration deployed and the service ${serviceDtls.name} is restarting in progress...`)
|
|
187
|
-
|
|
188
|
-
broker = brokerInit(val)
|
|
189
|
-
|
|
190
|
-
broker.createService(schema)
|
|
191
|
-
broker.start()
|
|
192
|
-
|
|
193
|
-
broker.logger.warn(`The service ${serviceDtls.name} restarted with new configuration.`)
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Service stop on backlist of the service from congiguration
|
|
198
|
-
*/
|
|
199
|
-
configHld.watchConfigs(`/config/sbk/global/members/${serviceDtls.name}`, async (ev, key, val) => {
|
|
200
|
-
broker.stop()
|
|
201
|
-
broker.logger.error(`The service ${serviceDtls.name} blacklisted and stopped.`)
|
|
202
|
-
process.exit(0)
|
|
203
|
-
|
|
204
|
-
})
|
|
238
|
+
createSbkServices(schema)
|
|
205
239
|
|
|
206
240
|
},
|
|
207
241
|
|
|
208
242
|
|
|
209
243
|
registerBridgeServices: async( type, brokerOpts = {}, callback = () => {}) => {
|
|
210
|
-
|
|
244
|
+
const { auxBrokerParamsValidator } = await import('#hUti/aux-broker-params-validator.mjs')
|
|
211
245
|
const {logLevel, gzip, msgPack, rest, ...opts} = brokerOpts
|
|
212
246
|
const paramObj = {type, opts, callback}
|
|
213
247
|
|
|
@@ -236,22 +270,14 @@ export default {
|
|
|
236
270
|
* Service create for kafka producer
|
|
237
271
|
* @type {object}
|
|
238
272
|
*/
|
|
239
|
-
validateServiceName(opts, serviceDtls.name)
|
|
240
273
|
if( opts.name.startsWith("producer") ){
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
)
|
|
274
|
+
createSbkServices(auxBroker.producer( opts, callback ))
|
|
275
|
+
|
|
244
276
|
}
|
|
245
277
|
else {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
)
|
|
278
|
+
createSbkServices(auxBroker.consumer( opts, callback ))
|
|
279
|
+
|
|
249
280
|
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Start broker
|
|
253
|
-
*/
|
|
254
|
-
broker.start()
|
|
255
281
|
|
|
256
282
|
},
|
|
257
283
|
|
package/package.json
CHANGED
|
@@ -5,9 +5,15 @@ import cookieParser from "cookie-parser"
|
|
|
5
5
|
import helmet from "helmet"
|
|
6
6
|
import compression from "compression"
|
|
7
7
|
|
|
8
|
-
import
|
|
8
|
+
import * as configHld from '#hUti/config-handler.mjs'
|
|
9
|
+
import {httpErrorFormatter} from '#hUti/error-handler.mjs'
|
|
9
10
|
import { initOpenId, authorize } from '#hUti/access-token-validator.mjs'
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Local configs
|
|
14
|
+
*/
|
|
15
|
+
const LC_PORT = (await configHld.getConfigs(`/config/sbk/members/gateway/envs/PORT`)) || 8765
|
|
16
|
+
|
|
11
17
|
export default {
|
|
12
18
|
name: "gateway",
|
|
13
19
|
mixins: [
|
|
@@ -22,7 +28,7 @@ export default {
|
|
|
22
28
|
},
|
|
23
29
|
|
|
24
30
|
settings: {
|
|
25
|
-
port:
|
|
31
|
+
port: LC_PORT,
|
|
26
32
|
|
|
27
33
|
/**
|
|
28
34
|
* Middleware mode (for ExpressJS)
|
|
@@ -129,7 +135,7 @@ export default {
|
|
|
129
135
|
*/
|
|
130
136
|
onError(req, res, err) {
|
|
131
137
|
|
|
132
|
-
|
|
138
|
+
httpErrorFormatter(req, res, err)
|
|
133
139
|
|
|
134
140
|
/**
|
|
135
141
|
* Custom logging
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Kafka, logLevel, Partitioners, CompressionTypes } from 'kafkajs'
|
|
2
2
|
import msgpack5 from 'msgpack5'
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import * as configHdl from '#hUti/config-handler.mjs'
|
|
5
5
|
|
|
6
6
|
const msgpack = msgpack5()
|
|
7
|
-
|
|
7
|
+
const KAFKA_CONFIG = await configHdl.getConfigs('/config/sbk/bridge/yaml/kafka')
|
|
8
8
|
|
|
9
9
|
const setKafkaConfig = (opts) => {
|
|
10
10
|
opts.logLevel = opts?.logLevel ?? KAFKA_CONFIG.logLevel
|
|
@@ -163,7 +163,7 @@ export const consumer = (opts, callback) => {
|
|
|
163
163
|
|
|
164
164
|
await consumer.subscribe({ topic: topicRegxObj, fromBeginning: true })
|
|
165
165
|
|
|
166
|
-
// for debug only
|
|
166
|
+
// for debug only to consume individual message
|
|
167
167
|
// await consumer.run({
|
|
168
168
|
// eachMessage: async ({ topic, partition, message }) => {
|
|
169
169
|
// const decoded = opts?.msgPack == false
|
|
@@ -8,11 +8,23 @@ import helmet from "helmet"
|
|
|
8
8
|
import scalarHTML from "./scalar.mjs"
|
|
9
9
|
import swStatsMw from "./sw-stats-mw.mjs"
|
|
10
10
|
import {
|
|
11
|
-
getConfig,
|
|
11
|
+
// getConfig,
|
|
12
12
|
assetPath,
|
|
13
13
|
// openApiConfig
|
|
14
14
|
} from '#hFil/esm-loading.mjs'
|
|
15
15
|
|
|
16
|
+
import * as configHld from '#hUti/config-handler.mjs'
|
|
17
|
+
import * as errHdl from '#hUti/error-handler.mjs'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Local configs
|
|
22
|
+
*/
|
|
23
|
+
const LC_PORT = (await configHld.getConfigs(`/config/sbk/members/system/envs/PORT`)) || 9876
|
|
24
|
+
const LC_BROADCAST_INTERVAL = await configHld.getConfigs(`/config/sbk/members/system/envs/BROADCAST_INTERVAL`)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
16
28
|
const CONFIG = {
|
|
17
29
|
mgmPort: 9876,
|
|
18
30
|
|
|
@@ -21,7 +33,7 @@ const CONFIG = {
|
|
|
21
33
|
*/
|
|
22
34
|
openApiInfo: [
|
|
23
35
|
{
|
|
24
|
-
url: `http://dev.sbk.wbsedcl.in:${
|
|
36
|
+
url: `http://dev.sbk.wbsedcl.in:${LC_PORT}`,
|
|
25
37
|
summary: "ESB",
|
|
26
38
|
description: "An API Gateway service provider."
|
|
27
39
|
}
|
|
@@ -43,11 +55,11 @@ export default {
|
|
|
43
55
|
name: "system",
|
|
44
56
|
mixins: [
|
|
45
57
|
ApiGateway,
|
|
46
|
-
OpenApi
|
|
58
|
+
// OpenApi
|
|
47
59
|
],
|
|
48
60
|
|
|
49
61
|
settings: {
|
|
50
|
-
port:
|
|
62
|
+
port: LC_PORT,
|
|
51
63
|
|
|
52
64
|
/**
|
|
53
65
|
* Global middlewares. Applied to all routes.
|
|
@@ -137,6 +149,11 @@ export default {
|
|
|
137
149
|
return ctx.call("$node.actions")
|
|
138
150
|
},
|
|
139
151
|
|
|
152
|
+
broadcastConfigRevision: async (ctx) => {
|
|
153
|
+
const CONFIG_REVISION = errHdl.validateConfRevision(await configHld.getConfigs(`/config/sbk/global/envs/REVISION`))
|
|
154
|
+
ctx.broker.broadcast("config.revisions", CONFIG_REVISION)
|
|
155
|
+
},
|
|
156
|
+
|
|
140
157
|
openApiSpec: (ctx) => {
|
|
141
158
|
return ctx.call("system.generateDocs")
|
|
142
159
|
},
|
|
@@ -180,17 +197,17 @@ export default {
|
|
|
180
197
|
* swagger-stats initialized with OpenAPI spec once the Gateway service started.
|
|
181
198
|
*/
|
|
182
199
|
async started() {
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Generate spec after service starts
|
|
186
|
-
*/
|
|
187
|
-
const spec = await this.actions.generateDocs()
|
|
188
200
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
201
|
+
// /**
|
|
202
|
+
// * Generate spec after service starts
|
|
203
|
+
// */
|
|
204
|
+
// const spec = await this.actions.generateDocs()
|
|
205
|
+
|
|
206
|
+
// /*Patch swagger-stats middleware with spec*/
|
|
207
|
+
// const swStats = this.settings.use.find(mw => mw.name === "swagger-stats")
|
|
208
|
+
// if (swStats && spec) {
|
|
209
|
+
// swStats.swaggerSpec = spec
|
|
210
|
+
// }
|
|
194
211
|
|
|
195
212
|
/**
|
|
196
213
|
* add endpoints
|
|
@@ -237,7 +254,63 @@ export default {
|
|
|
237
254
|
* Redirect to redpanda web client
|
|
238
255
|
*/
|
|
239
256
|
"GET /redpanda": "system.redpandaUi",
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
*
|
|
260
|
+
*/
|
|
261
|
+
"GET /config/revision/brodcast/immediate": "system.broadcastConfigRevision",
|
|
240
262
|
}
|
|
241
263
|
})
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
this.interval = setInterval(async () => {
|
|
267
|
+
const CONFIG_REVISION = errHdl.validateConfRevision(await configHld.getConfigs(`/config/sbk/global/envs/REVISION`))
|
|
268
|
+
this.broker.logger.debug(CONFIG_REVISION, {message: `Brodcast Config revisions ${Date.now()}`})
|
|
269
|
+
this.broker.broadcast("config.revisions", CONFIG_REVISION)
|
|
270
|
+
}, LC_BROADCAST_INTERVAL)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
configHld.watchConfigs('/config/sbk/', async (ev, key, val) => {
|
|
275
|
+
if( key == "/config/sbk/global/envs/REVISION" ){
|
|
276
|
+
return false
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const CONFIG_REVISION = errHdl.validateConfRevision(await configHld.getConfigs(`/config/sbk/global/envs/REVISION`))
|
|
280
|
+
|
|
281
|
+
if( /^\/config\/sbk\/members\/[^/]+$/.test(key) && /^false$/i.test(val) ){
|
|
282
|
+
const serviceName = key.replace("/config/sbk/members/","")
|
|
283
|
+
CONFIG_REVISION.mem[serviceName] = -1
|
|
284
|
+
this.broker.broadcast("config.revisions", CONFIG_REVISION)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if( /^\/config\/sbk\/members\/[^/]+$/.test(key) && /^true$/i.test(val) ){
|
|
288
|
+
const serviceName = key.replace("/config/sbk/members/","")
|
|
289
|
+
CONFIG_REVISION.mem[serviceName] = 0
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if( /^\/config\/sbk\/members\/[^/]+\/.+$/.test(key) ){
|
|
293
|
+
const memRegex = /^\/config\/sbk\/members\/([^/]+)\/.+$/
|
|
294
|
+
const serviceName = (key.match(memRegex))[1]
|
|
295
|
+
|
|
296
|
+
CONFIG_REVISION.mem[serviceName] = CONFIG_REVISION.mem[serviceName] == undefined
|
|
297
|
+
? 0
|
|
298
|
+
: CONFIG_REVISION.mem[serviceName] >= 0
|
|
299
|
+
? CONFIG_REVISION.mem[serviceName] + 1
|
|
300
|
+
: CONFIG_REVISION.mem[serviceName]
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if( key.startsWith("/config/sbk/global/") ){
|
|
304
|
+
CONFIG_REVISION.pub++
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if( key.startsWith("/config/sbk/edge/") ){
|
|
308
|
+
CONFIG_REVISION.edg++
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
await configHld.putConfig("/config/sbk/global/envs/REVISION", JSON.stringify(CONFIG_REVISION))
|
|
312
|
+
this.broker.logger.debug( {message: "Config revised"}, CONFIG_REVISION )
|
|
313
|
+
})
|
|
314
|
+
|
|
242
315
|
},
|
|
243
316
|
}
|