underpost 2.8.646 → 2.8.652
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/.vscode/extensions.json +0 -1
- package/README.md +39 -2
- package/bin/deploy.js +44 -1
- package/bin/file.js +8 -0
- package/bin/index.js +1 -233
- package/cli.md +439 -0
- package/docker-compose.yml +1 -1
- package/jsdoc.json +1 -1
- package/package.json +1 -1
- package/src/api/user/user.service.js +13 -10
- package/src/cli/cluster.js +45 -2
- package/src/cli/db.js +18 -8
- package/src/cli/deploy.js +109 -54
- package/src/cli/index.js +300 -0
- package/src/cli/monitor.js +110 -11
- package/src/client/components/core/Account.js +3 -3
- package/src/client/components/core/Css.js +0 -1
- package/src/client/components/core/CssCore.js +2 -0
- package/src/client/components/core/EventsUI.js +1 -1
- package/src/client/components/core/RichText.js +1 -11
- package/src/index.js +1 -1
- package/src/mailer/MailerProvider.js +3 -0
- package/src/server/client-build.js +13 -0
- package/src/server/conf.js +44 -0
- package/src/server/runtime.js +5 -0
- package/src/server/start.js +16 -9
- package/src/server/valkey.js +25 -11
package/src/cli/monitor.js
CHANGED
|
@@ -4,13 +4,32 @@ import UnderpostDeploy from './deploy.js';
|
|
|
4
4
|
import axios from 'axios';
|
|
5
5
|
import UnderpostRootEnv from './env.js';
|
|
6
6
|
import fs from 'fs-extra';
|
|
7
|
+
import { shellExec } from '../server/process.js';
|
|
7
8
|
|
|
8
9
|
const logger = loggerFactory(import.meta);
|
|
9
10
|
|
|
10
11
|
class UnderpostMonitor {
|
|
11
12
|
static API = {
|
|
12
|
-
async callback(
|
|
13
|
-
|
|
13
|
+
async callback(
|
|
14
|
+
deployId,
|
|
15
|
+
env = 'development',
|
|
16
|
+
options = { now: false, single: false, msInterval: '', type: '' },
|
|
17
|
+
commanderOptions,
|
|
18
|
+
auxRouter,
|
|
19
|
+
) {
|
|
20
|
+
if (deployId === 'dd' && fs.existsSync(`./engine-private/deploy/dd.router`)) {
|
|
21
|
+
for (const _deployId of fs.readFileSync(`./engine-private/deploy/dd.router`, 'utf8').split(','))
|
|
22
|
+
UnderpostMonitor.API.callback(
|
|
23
|
+
_deployId.trim(),
|
|
24
|
+
env,
|
|
25
|
+
options,
|
|
26
|
+
commanderOptions,
|
|
27
|
+
await UnderpostDeploy.API.routerFactory(_deployId, env),
|
|
28
|
+
);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const router = auxRouter ?? (await UnderpostDeploy.API.routerFactory(deployId, env));
|
|
14
33
|
|
|
15
34
|
const confServer = loadReplicas(
|
|
16
35
|
JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
|
|
@@ -19,20 +38,30 @@ class UnderpostMonitor {
|
|
|
19
38
|
|
|
20
39
|
const pathPortAssignmentData = pathPortAssignmentFactory(router, confServer);
|
|
21
40
|
|
|
22
|
-
logger.info(
|
|
41
|
+
logger.info(`${deployId} ${env}`, pathPortAssignmentData);
|
|
23
42
|
|
|
24
|
-
|
|
43
|
+
let errorPayloads = [];
|
|
44
|
+
let traffic = 'blue';
|
|
25
45
|
const maxAttempts = Object.keys(pathPortAssignmentData)
|
|
26
46
|
.map((host) => pathPortAssignmentData[host].length)
|
|
27
47
|
.reduce((accumulator, value) => accumulator + value, 0);
|
|
28
48
|
|
|
29
49
|
const monitor = async (reject) => {
|
|
30
|
-
logger.info(
|
|
50
|
+
logger.info(`[${deployId}-${env}] Check server health`);
|
|
31
51
|
for (const host of Object.keys(pathPortAssignmentData)) {
|
|
32
52
|
for (const instance of pathPortAssignmentData[host]) {
|
|
33
53
|
const { port, path } = instance;
|
|
34
54
|
if (path.match('peer') || path.match('socket')) continue;
|
|
35
|
-
|
|
55
|
+
let urlTest = `http://localhost:${port}${path}`;
|
|
56
|
+
switch (options.type) {
|
|
57
|
+
case 'remote':
|
|
58
|
+
case 'blue-green':
|
|
59
|
+
urlTest = `https://${host}${path}`;
|
|
60
|
+
break;
|
|
61
|
+
|
|
62
|
+
default:
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
36
65
|
// logger.info('Test instance', urlTest);
|
|
37
66
|
await axios.get(urlTest, { timeout: 10000 }).catch((error) => {
|
|
38
67
|
// console.log(error);
|
|
@@ -50,8 +79,42 @@ class UnderpostMonitor {
|
|
|
50
79
|
errorPayloads.push(errorPayload);
|
|
51
80
|
if (errorPayloads.length >= maxAttempts) {
|
|
52
81
|
const message = JSON.stringify(errorPayloads, null, 4);
|
|
53
|
-
|
|
54
|
-
|
|
82
|
+
logger.error(
|
|
83
|
+
`Deployment ${deployId} ${env} has been reached max attempts error payloads`,
|
|
84
|
+
errorPayloads,
|
|
85
|
+
);
|
|
86
|
+
switch (options.type) {
|
|
87
|
+
case 'blue-green':
|
|
88
|
+
{
|
|
89
|
+
const confServer = JSON.parse(
|
|
90
|
+
fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8'),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
for (const host of Object.keys(confServer)) {
|
|
94
|
+
shellExec(`sudo kubectl delete HTTPProxy ${host}`);
|
|
95
|
+
}
|
|
96
|
+
shellExec(`sudo kubectl rollout restart deployment/${deployId}-${env}-${traffic}`);
|
|
97
|
+
|
|
98
|
+
if (traffic === 'blue') traffic = 'green';
|
|
99
|
+
else traffic = 'blue';
|
|
100
|
+
|
|
101
|
+
shellExec(
|
|
102
|
+
`node bin deploy --info-router --build-manifest --traffic ${traffic} ${deployId} ${env}`,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
shellExec(`sudo kubectl apply -f ./engine-private/conf/${deployId}/build/${env}/proxy.yaml`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
break;
|
|
109
|
+
|
|
110
|
+
case 'remote':
|
|
111
|
+
break;
|
|
112
|
+
|
|
113
|
+
default:
|
|
114
|
+
if (reject) reject(message);
|
|
115
|
+
else throw new Error(message);
|
|
116
|
+
}
|
|
117
|
+
errorPayloads = [];
|
|
55
118
|
}
|
|
56
119
|
logger.error('Error accumulator', errorPayloads.length);
|
|
57
120
|
}
|
|
@@ -63,11 +126,47 @@ class UnderpostMonitor {
|
|
|
63
126
|
if (options.single === true) return;
|
|
64
127
|
let optionsMsTimeout = parseInt(options.msInterval);
|
|
65
128
|
if (isNaN(optionsMsTimeout)) optionsMsTimeout = 30000;
|
|
129
|
+
let monitorTrafficName;
|
|
130
|
+
let monitorPodName;
|
|
66
131
|
const monitorCallBack = (resolve, reject) => {
|
|
67
|
-
const envMsTimeout = UnderpostRootEnv.API.get(
|
|
132
|
+
const envMsTimeout = UnderpostRootEnv.API.get(`${deployId}-${env}-monitor-ms`);
|
|
68
133
|
setTimeout(
|
|
69
134
|
async () => {
|
|
70
|
-
switch (
|
|
135
|
+
switch (options.type) {
|
|
136
|
+
case 'blue-green':
|
|
137
|
+
{
|
|
138
|
+
if (monitorTrafficName !== traffic) {
|
|
139
|
+
monitorTrafficName = undefined;
|
|
140
|
+
monitorPodName = undefined;
|
|
141
|
+
}
|
|
142
|
+
const cmd = `underpost config get container-status`;
|
|
143
|
+
const checkDeploymentReadyStatus = () => {
|
|
144
|
+
const pods = UnderpostDeploy.API.get(`${deployId}-${env}-${traffic}`);
|
|
145
|
+
if (pods && pods[0]) {
|
|
146
|
+
const { NAME } = pods[0];
|
|
147
|
+
if (
|
|
148
|
+
shellExec(`sudo kubectl exec -i ${NAME} -- sh -c "${cmd}"`, { stdout: true }).match(
|
|
149
|
+
`${deployId}-${env}-running-deployment`,
|
|
150
|
+
)
|
|
151
|
+
) {
|
|
152
|
+
monitorPodName = NAME;
|
|
153
|
+
monitorTrafficName = `${traffic}`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
if (!monitorPodName) {
|
|
158
|
+
checkDeploymentReadyStatus();
|
|
159
|
+
monitorCallBack(resolve, reject);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
break;
|
|
165
|
+
|
|
166
|
+
default:
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
switch (UnderpostRootEnv.API.get(`${deployId}-${env}-monitor-input`)) {
|
|
71
170
|
case 'pause':
|
|
72
171
|
monitorCallBack(resolve, reject);
|
|
73
172
|
return;
|
|
@@ -84,7 +183,7 @@ class UnderpostMonitor {
|
|
|
84
183
|
!isNaN(envMsTimeout) ? envMsTimeout : optionsMsTimeout,
|
|
85
184
|
);
|
|
86
185
|
};
|
|
87
|
-
return
|
|
186
|
+
return new Promise((...args) => monitorCallBack(...args));
|
|
88
187
|
},
|
|
89
188
|
};
|
|
90
189
|
}
|
|
@@ -204,7 +204,7 @@ const Account = {
|
|
|
204
204
|
disabled: false,
|
|
205
205
|
extension: async () =>
|
|
206
206
|
html`${await BtnIcon.Render({
|
|
207
|
-
class: `wfa btn-input-extension btn-account-update-username`,
|
|
207
|
+
class: `in wfa btn-input-extension btn-account-update-username`,
|
|
208
208
|
type: 'button',
|
|
209
209
|
style: 'text-align: left',
|
|
210
210
|
label: html`${Translate.Render(`update`)}`,
|
|
@@ -223,7 +223,7 @@ const Account = {
|
|
|
223
223
|
extension: !(options && options.disabled && options.disabled.includes('emailConfirm'))
|
|
224
224
|
? async () => html`<div class="in verify-email-status"></div>
|
|
225
225
|
${await BtnIcon.Render({
|
|
226
|
-
class: `wfa btn-input-extension btn-confirm-email`,
|
|
226
|
+
class: `in wfa btn-input-extension btn-confirm-email`,
|
|
227
227
|
type: 'button',
|
|
228
228
|
style: 'text-align: left',
|
|
229
229
|
label: html`<div class="in">
|
|
@@ -246,7 +246,7 @@ const Account = {
|
|
|
246
246
|
disabledEye: true,
|
|
247
247
|
extension: async () =>
|
|
248
248
|
html`${await BtnIcon.Render({
|
|
249
|
-
class: `wfa btn-input-extension btn-account-change-password`,
|
|
249
|
+
class: `in wfa btn-input-extension btn-account-change-password`,
|
|
250
250
|
type: 'button',
|
|
251
251
|
style: 'text-align: left',
|
|
252
252
|
label: html`${Translate.Render(`change-password`)}`,
|
|
@@ -761,7 +761,6 @@ const renderWave = ({ id }) => {
|
|
|
761
761
|
const cssTokensEffect = {};
|
|
762
762
|
const cssTokensContainer = {};
|
|
763
763
|
const cssEffect = async (containerSelector, event) => {
|
|
764
|
-
return;
|
|
765
764
|
// Array.from(event.target.classList)
|
|
766
765
|
let offsetX, offsetY;
|
|
767
766
|
if (Array.from(event.srcElement.classList).includes('ripple') && cssTokensContainer[containerSelector]) {
|
|
@@ -524,6 +524,7 @@ const CssCoreDark = {
|
|
|
524
524
|
margin: 5px 0 0 0;
|
|
525
525
|
padding: 5px;
|
|
526
526
|
font-size: 16px;
|
|
527
|
+
min-height: 40px;
|
|
527
528
|
}
|
|
528
529
|
.btn-input-extension:hover {
|
|
529
530
|
}
|
|
@@ -843,6 +844,7 @@ const CssCoreLight = {
|
|
|
843
844
|
margin: 5px 0 0 0;
|
|
844
845
|
padding: 5px;
|
|
845
846
|
font-size: 16px;
|
|
847
|
+
min-height: 40px;
|
|
846
848
|
}
|
|
847
849
|
.btn-input-extension:hover {
|
|
848
850
|
}
|
|
@@ -12,7 +12,7 @@ const EventsUI = {
|
|
|
12
12
|
if (!s(id)) return;
|
|
13
13
|
let complete = true;
|
|
14
14
|
s(id)[type] = async function (e) {
|
|
15
|
-
cssEffect(id, e);
|
|
15
|
+
if (options.clickEffect) cssEffect(id, e);
|
|
16
16
|
if (complete) {
|
|
17
17
|
complete = false;
|
|
18
18
|
await LoadingAnimation.spinner.play(loadingContainer ? loadingContainer : id);
|
|
@@ -7,28 +7,18 @@ const RichText = {
|
|
|
7
7
|
Render: async function (options = { id: '', parentIdModal: '' }) {
|
|
8
8
|
const id = options?.id ? options.id : getId(this.Tokens, 'rich-text-');
|
|
9
9
|
this.Tokens[id] = {};
|
|
10
|
-
let top, height;
|
|
11
10
|
setTimeout(() => {
|
|
12
11
|
const easyMDE = new EasyMDE({
|
|
13
12
|
element: s(`.${id}`),
|
|
13
|
+
hideIcons: ['fullscreen', 'side-by-side'],
|
|
14
14
|
onToggleFullScreen: (onFs) => {
|
|
15
15
|
if (onFs) {
|
|
16
16
|
if (options.parentIdModal) {
|
|
17
|
-
s(`.btn-bar-modal-container-${options.parentIdModal}`).classList.add('hide');
|
|
18
|
-
top = newInstance(s(`.${options.parentIdModal}`).style.top);
|
|
19
|
-
height = newInstance(s(`.${options.parentIdModal}`).style.height);
|
|
20
|
-
s(`.${options.parentIdModal}`).style.top = '0px';
|
|
21
|
-
s(`.${options.parentIdModal}`).style.height = `${window.innerHeight}px`;
|
|
22
17
|
}
|
|
23
18
|
// Modal.cleanUI();
|
|
24
|
-
if (s(`.slide-menu-top-bar`)) s(`.slide-menu-top-bar`).classList.add('hide');
|
|
25
19
|
} else {
|
|
26
20
|
if (options.parentIdModal) {
|
|
27
|
-
s(`.btn-bar-modal-container-${options.parentIdModal}`).classList.remove('hide');
|
|
28
|
-
s(`.${options.parentIdModal}`).style.top = top;
|
|
29
|
-
s(`.${options.parentIdModal}`).style.height = height;
|
|
30
21
|
}
|
|
31
|
-
if (s(`.slide-menu-top-bar`)) s(`.slide-menu-top-bar`).classList.add('remove');
|
|
32
22
|
// Modal.restoreUI();
|
|
33
23
|
}
|
|
34
24
|
},
|
package/src/index.js
CHANGED
|
@@ -32,6 +32,9 @@ const MailerProvider = {
|
|
|
32
32
|
},
|
|
33
33
|
) {
|
|
34
34
|
try {
|
|
35
|
+
options.transport.tls = {
|
|
36
|
+
rejectUnauthorized: false,
|
|
37
|
+
};
|
|
35
38
|
const { id } = options;
|
|
36
39
|
// Generate test SMTP service account from ethereal.email
|
|
37
40
|
// Only needed if you don't have a real mail account for testing
|
|
@@ -683,6 +683,19 @@ Sitemap: https://${host}${path === '/' ? '' : path}/sitemap.xml`,
|
|
|
683
683
|
root file where the route starts, such as index.js, app.js, routes.js, etc ... */
|
|
684
684
|
|
|
685
685
|
await swaggerAutoGen({ openapi: '3.0.0' })(outputFile, routes, doc);
|
|
686
|
+
|
|
687
|
+
const htmlFiles = await fs.readdir(`./public/${host}/docs/engine/${Underpost.version.replace('v', '')}`);
|
|
688
|
+
for (const htmlFile of htmlFiles) {
|
|
689
|
+
if (htmlFile.match('.html')) {
|
|
690
|
+
fs.writeFileSync(
|
|
691
|
+
`./public/${host}/docs/engine/${Underpost.version.replace('v', '')}/${htmlFile}`,
|
|
692
|
+
fs
|
|
693
|
+
.readFileSync(`./public/${host}/docs/engine/${Underpost.version.replace('v', '')}/${htmlFile}`, 'utf8')
|
|
694
|
+
.replaceAll('Tutorials', 'References'),
|
|
695
|
+
'utf8',
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
686
699
|
}
|
|
687
700
|
|
|
688
701
|
if (client) {
|
package/src/server/conf.js
CHANGED
|
@@ -923,6 +923,49 @@ const mergeFile = async (parts = [], outputFilePath) => {
|
|
|
923
923
|
});
|
|
924
924
|
};
|
|
925
925
|
|
|
926
|
+
const rebuildConfFactory = ({ deployId, valkey, mongo }) => {
|
|
927
|
+
const confServer = loadReplicas(
|
|
928
|
+
JSON.parse(fs.readFileSync(`./engine-private/conf/${deployId}/conf.server.json`, 'utf8')),
|
|
929
|
+
);
|
|
930
|
+
for (const host of Object.keys(confServer)) {
|
|
931
|
+
for (const path of Object.keys(confServer[host])) {
|
|
932
|
+
if (!confServer[host][path].db) continue;
|
|
933
|
+
const { singleReplica, replicas, db } = confServer[host][path];
|
|
934
|
+
const { provider } = db;
|
|
935
|
+
if (singleReplica) {
|
|
936
|
+
for (const replica of replicas) {
|
|
937
|
+
const deployIdReplica = buildReplicaId({ replica, deployId });
|
|
938
|
+
const confServerReplica = JSON.parse(
|
|
939
|
+
fs.readFileSync(`./engine-private/replica/${deployIdReplica}/conf.server.json`, 'utf8'),
|
|
940
|
+
);
|
|
941
|
+
for (const _host of Object.keys(confServerReplica)) {
|
|
942
|
+
for (const _path of Object.keys(confServerReplica[_host])) {
|
|
943
|
+
confServerReplica[_host][_path].valkey = valkey;
|
|
944
|
+
switch (provider) {
|
|
945
|
+
case 'mongoose':
|
|
946
|
+
confServerReplica[_host][_path].db.host = mongo.host;
|
|
947
|
+
break;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
fs.writeFileSync(
|
|
952
|
+
`./engine-private/replica/${deployIdReplica}/conf.server.json`,
|
|
953
|
+
JSON.stringify(confServerReplica, null, 4),
|
|
954
|
+
'utf8',
|
|
955
|
+
);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
confServer[host][path].valkey = valkey;
|
|
959
|
+
switch (provider) {
|
|
960
|
+
case 'mongoose':
|
|
961
|
+
confServer[host][path].db.host = mongo.host;
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
fs.writeFileSync(`./engine-private/conf/${deployId}/conf.server.json`, JSON.stringify(confServer, null, 4), 'utf8');
|
|
967
|
+
};
|
|
968
|
+
|
|
926
969
|
const getRestoreCronCmd = async (options = { host: '', path: '', conf: {}, deployId: '' }) => {
|
|
927
970
|
const { host, path, conf, deployId } = options;
|
|
928
971
|
const { runtime, db, git, directory } = conf[host][path];
|
|
@@ -1166,4 +1209,5 @@ export {
|
|
|
1166
1209
|
pathPortAssignmentFactory,
|
|
1167
1210
|
deployRangePortFactory,
|
|
1168
1211
|
awaitDeployMonitor,
|
|
1212
|
+
rebuildConfFactory,
|
|
1169
1213
|
};
|
package/src/server/runtime.js
CHANGED
|
@@ -21,6 +21,7 @@ import { Lampp } from '../runtime/lampp/Lampp.js';
|
|
|
21
21
|
import { getDeployId } from './conf.js';
|
|
22
22
|
import { JSONweb, ssrFactory } from './client-formatted.js';
|
|
23
23
|
import Underpost from '../index.js';
|
|
24
|
+
import { createValkeyConnection } from './valkey.js';
|
|
24
25
|
|
|
25
26
|
dotenv.config();
|
|
26
27
|
|
|
@@ -67,6 +68,7 @@ const buildRuntime = async () => {
|
|
|
67
68
|
peer,
|
|
68
69
|
singleReplica,
|
|
69
70
|
replicas,
|
|
71
|
+
valkey,
|
|
70
72
|
} = confServer[host][path];
|
|
71
73
|
|
|
72
74
|
if (singleReplica && replicas && replicas.length > 0 && !singleReplicaHosts.includes(host)) {
|
|
@@ -361,6 +363,9 @@ const buildRuntime = async () => {
|
|
|
361
363
|
|
|
362
364
|
if (db && apis) await DataBaseProvider.load({ apis, host, path, db });
|
|
363
365
|
|
|
366
|
+
// valkey server
|
|
367
|
+
await createValkeyConnection({ host, path }, valkey);
|
|
368
|
+
|
|
364
369
|
if (mailer) {
|
|
365
370
|
const mailerSsrConf = confSSR[getCapVariableName(client)];
|
|
366
371
|
await MailerProvider.load({
|
package/src/server/start.js
CHANGED
|
@@ -4,6 +4,7 @@ import fs from 'fs-extra';
|
|
|
4
4
|
import { awaitDeployMonitor } from './conf.js';
|
|
5
5
|
import { actionInitLog, loggerFactory } from './logger.js';
|
|
6
6
|
import { shellCd, shellExec } from './process.js';
|
|
7
|
+
import UnderpostRootEnv from '../cli/env.js';
|
|
7
8
|
|
|
8
9
|
const logger = loggerFactory(import.meta);
|
|
9
10
|
|
|
@@ -20,14 +21,20 @@ class UnderpostStartUp {
|
|
|
20
21
|
},
|
|
21
22
|
listenServerFactory: (logic = async () => {}) => {
|
|
22
23
|
return {
|
|
23
|
-
listen: async (...args) =>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
listen: async (...args) => {
|
|
25
|
+
const msDelta = 1000;
|
|
26
|
+
const msMax = 30 * 24 * 60 * 60 * 1000; // ~ 1 month
|
|
27
|
+
let msCount = 0;
|
|
28
|
+
setInterval(() => {
|
|
29
|
+
msCount += msDelta;
|
|
30
|
+
if (msCount >= msMax) {
|
|
31
|
+
const message = 'Listen server factory timeout';
|
|
32
|
+
logger.error(message);
|
|
33
|
+
throw new Error(message);
|
|
34
|
+
}
|
|
35
|
+
}, msDelta);
|
|
36
|
+
return logic ? await logic(...args) : undefined, args[1]();
|
|
37
|
+
},
|
|
31
38
|
};
|
|
32
39
|
},
|
|
33
40
|
listenPortController: async (server, port, metadata) =>
|
|
@@ -108,7 +115,7 @@ class UnderpostStartUp {
|
|
|
108
115
|
shellExec(`node bin/deploy conf ${deployId} ${env}`);
|
|
109
116
|
shellExec(`npm ${runCmd} deploy deploy-id:${deployId}`, { async: true });
|
|
110
117
|
await awaitDeployMonitor(true);
|
|
111
|
-
|
|
118
|
+
UnderpostRootEnv.API.set('container-status', `${deployId}-${env}-running-deployment`);
|
|
112
119
|
},
|
|
113
120
|
};
|
|
114
121
|
}
|
package/src/server/valkey.js
CHANGED
|
@@ -5,12 +5,24 @@ import { loggerFactory } from './logger.js';
|
|
|
5
5
|
|
|
6
6
|
const logger = loggerFactory(import.meta);
|
|
7
7
|
|
|
8
|
+
const ValkeyInstances = {};
|
|
9
|
+
|
|
8
10
|
let valkeyEnabled = true;
|
|
9
11
|
|
|
10
12
|
const disableValkeyErrorMessage = 'valkey is not enabled';
|
|
11
13
|
|
|
12
14
|
const isValkeyEnable = () => valkeyEnabled;
|
|
13
15
|
|
|
16
|
+
const createValkeyConnection = async (
|
|
17
|
+
instance = { host: '', port: 0 },
|
|
18
|
+
valkeyServerConnectionOptions = { host: '', port: 0 },
|
|
19
|
+
) => {
|
|
20
|
+
ValkeyInstances[`${instance.host}${instance.path}`] = await ValkeyAPI.valkeyClientFactory(
|
|
21
|
+
valkeyServerConnectionOptions,
|
|
22
|
+
);
|
|
23
|
+
return ValkeyInstances[`${instance.host}${instance.path}`];
|
|
24
|
+
};
|
|
25
|
+
|
|
14
26
|
const selectDtoFactory = (payload, select) => {
|
|
15
27
|
const result = {};
|
|
16
28
|
for (const key of Object.keys(select)) {
|
|
@@ -19,10 +31,12 @@ const selectDtoFactory = (payload, select) => {
|
|
|
19
31
|
return result;
|
|
20
32
|
};
|
|
21
33
|
|
|
22
|
-
const valkeyClientFactory = async () => {
|
|
34
|
+
const valkeyClientFactory = async (options) => {
|
|
23
35
|
const valkey = new Valkey({
|
|
24
36
|
// port: 6379,
|
|
25
37
|
// host: 'service-valkey.default.svc.cluster.local',
|
|
38
|
+
port: options?.port ? options.port : undefined,
|
|
39
|
+
host: options?.port ? options.host : undefined,
|
|
26
40
|
retryStrategy: (attempt) => {
|
|
27
41
|
if (attempt === 1) {
|
|
28
42
|
valkey.disconnect();
|
|
@@ -46,12 +60,12 @@ const valkeyClientFactory = async () => {
|
|
|
46
60
|
return valkey;
|
|
47
61
|
};
|
|
48
62
|
|
|
49
|
-
const getValkeyObject = async (key = '') => {
|
|
63
|
+
const getValkeyObject = async (options = { host: '', port: 0 }, key = '') => {
|
|
50
64
|
if (!valkeyEnabled) {
|
|
51
65
|
logger.warn(disableValkeyErrorMessage + ' get', key);
|
|
52
66
|
return null;
|
|
53
67
|
}
|
|
54
|
-
const object = await
|
|
68
|
+
const object = await ValkeyInstances[`${options.host}${options.path}`].get(key);
|
|
55
69
|
try {
|
|
56
70
|
return JSON.parse(object);
|
|
57
71
|
} catch (error) {
|
|
@@ -60,19 +74,19 @@ const getValkeyObject = async (key = '') => {
|
|
|
60
74
|
}
|
|
61
75
|
};
|
|
62
76
|
|
|
63
|
-
const setValkeyObject = async (key = '', payload = {}) => {
|
|
77
|
+
const setValkeyObject = async (options = { host: '', port: 0 }, key = '', payload = {}) => {
|
|
64
78
|
if (!valkeyEnabled) throw new Error(disableValkeyErrorMessage);
|
|
65
|
-
return await
|
|
79
|
+
return await ValkeyInstances[`${options.host}${options.path}`].set(key, JSON.stringify(payload));
|
|
66
80
|
};
|
|
67
81
|
|
|
68
|
-
const updateValkeyObject = async (key = '', payload = {}) => {
|
|
82
|
+
const updateValkeyObject = async (options = { host: '', port: 0 }, key = '', payload = {}) => {
|
|
69
83
|
if (!valkeyEnabled) throw new Error(disableValkeyErrorMessage);
|
|
70
|
-
const object = await getValkeyObject(key
|
|
84
|
+
const object = await getValkeyObject(key);
|
|
71
85
|
object.updatedAt = new Date().toISOString();
|
|
72
|
-
return await
|
|
86
|
+
return await ValkeyInstances[`${options.host}${options.path}`].set(key, JSON.stringify({ ...object, ...payload }));
|
|
73
87
|
};
|
|
74
88
|
|
|
75
|
-
const valkeyObjectFactory = async (
|
|
89
|
+
const valkeyObjectFactory = async (options = { host: 'localhost', object: {} }, module = '') => {
|
|
76
90
|
if (!valkeyEnabled) throw new Error(disableValkeyErrorMessage);
|
|
77
91
|
const idoDate = new Date().toISOString();
|
|
78
92
|
options.object = options.object || {};
|
|
@@ -112,10 +126,9 @@ const ValkeyAPI = {
|
|
|
112
126
|
setValkeyObject,
|
|
113
127
|
valkeyObjectFactory,
|
|
114
128
|
updateValkeyObject,
|
|
129
|
+
createValkeyConnection,
|
|
115
130
|
};
|
|
116
131
|
|
|
117
|
-
const valkey = await ValkeyAPI.valkeyClientFactory();
|
|
118
|
-
|
|
119
132
|
export {
|
|
120
133
|
valkeyClientFactory,
|
|
121
134
|
selectDtoFactory,
|
|
@@ -124,5 +137,6 @@ export {
|
|
|
124
137
|
valkeyObjectFactory,
|
|
125
138
|
updateValkeyObject,
|
|
126
139
|
isValkeyEnable,
|
|
140
|
+
createValkeyConnection,
|
|
127
141
|
ValkeyAPI,
|
|
128
142
|
};
|