create-dacosta-proj 1.0.27 → 1.0.29
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
CHANGED
|
@@ -26,6 +26,7 @@ const targets = new Array(servers).fill().map((_, server) => {
|
|
|
26
26
|
password: process.env[`DEPLOY_${server+1}_PASSWORD`],
|
|
27
27
|
path: process.env[`DEPLOY_${server+1}_PATH`],
|
|
28
28
|
src: process.env[`DEPLOY_${server+1}_PM2_SRC`],
|
|
29
|
+
nodejs: process.env[`DEPLOY_${server+1}_NODEJS`],
|
|
29
30
|
pm2,
|
|
30
31
|
};
|
|
31
32
|
});
|
|
@@ -74,8 +75,15 @@ async function restartOn(server) {
|
|
|
74
75
|
console.error(` ✗ ${name} — ${result.stderr || result.stdout}`);
|
|
75
76
|
}
|
|
76
77
|
} else {
|
|
78
|
+
|
|
79
|
+
if (server.nodejs) {
|
|
80
|
+
const node = await ssh.execCommand(withNvm(`nvm ls ${server.nodejs} > /dev/null 2>&1 || nvm install ${server.nodejs}`));
|
|
81
|
+
if (node.code === 0) console.log(` ✓ node ${server.nodejs}`);
|
|
82
|
+
else console.error(` ✗ node ${server.nodejs} — ${node.stderr || node.stdout}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
77
85
|
const result = await ssh.execCommand(
|
|
78
|
-
withNvm(`${args ? `${args} ` : ''}pm2 start ${server.src} --name "${name}" --log-date-format "YYYY-MM-DD HH:mm"`),
|
|
86
|
+
withNvm(`${server.nodejs ? `nvm use ${server.nodejs} && ` : ''}${args ? `${args} ` : ''}pm2 start ${server.src} --name "${name}" --log-date-format "YYYY-MM-DD HH:mm" --interpreter $(which node)`),
|
|
79
87
|
{ cwd: server.path }
|
|
80
88
|
);
|
|
81
89
|
if (result.code === 0) {
|
package/template/.env.template
CHANGED
|
@@ -14,6 +14,7 @@ DEPLOY_1_PM2_SRC=src/index.js
|
|
|
14
14
|
DEPLOY_1_PM2_ARGS= # Optional
|
|
15
15
|
# EXAMPLE 1: DEPLOY_1_PM2_ARGS=PROJECT_INSTANCE_ID=1 PROJECT_INSTANCE_TYPE=video
|
|
16
16
|
# EXAMPLE 2: DEPLOY_1_PM2_ARGS=PROJECT_INSTANCE_ID=1 PROJECT_INSTANCE_TYPE=video;PROJECT_INSTANCE_ID=1 PROJECT_INSTANCE_TYPE=live
|
|
17
|
+
DEPLOY_1_NODEJS=22.22.3
|
|
17
18
|
|
|
18
19
|
# Supabase
|
|
19
20
|
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* db: import('simple-supabase').DB | null,
|
|
4
4
|
* supabase: import('@supabase/supabase-js').SupabaseClient | null,
|
|
5
5
|
* redis: import('redis').RedisClientType | null,
|
|
6
|
-
* redisLock: ((lockName: string, timeout?: number) => Promise<() => Promise<void>>) | null,
|
|
7
6
|
* }}
|
|
8
7
|
*/
|
|
9
8
|
|
|
@@ -11,6 +10,5 @@ const global = {
|
|
|
11
10
|
db: null,
|
|
12
11
|
supabase: null,
|
|
13
12
|
redis: null,
|
|
14
|
-
redisLock: null,
|
|
15
13
|
};
|
|
16
14
|
module.exports = { global };
|
|
@@ -5,7 +5,6 @@ const { global } = require('@/config/global');
|
|
|
5
5
|
const { SimpleSupabase } = require('simple-supabase');
|
|
6
6
|
const { createClient: createSupabaseClient } = require('@supabase/supabase-js');
|
|
7
7
|
const { createClient: createRedisClient } = require('redis');
|
|
8
|
-
const redisLock = require('@/helpers/redisLock');
|
|
9
8
|
const wait = require('./wait');
|
|
10
9
|
|
|
11
10
|
module.exports = async () => {
|
|
@@ -17,7 +16,7 @@ module.exports = async () => {
|
|
|
17
16
|
|
|
18
17
|
let db = await SimpleSupabase({
|
|
19
18
|
credentials: { projectUrl, serviceKey },
|
|
20
|
-
redisPrefix: process.env.PROJECT_ID
|
|
19
|
+
redisPrefix: `${process.env.PROJECT_ID}${dev ? '_dev' : ''}`
|
|
21
20
|
});
|
|
22
21
|
|
|
23
22
|
const supabase = createSupabaseClient(projectUrl, serviceKey, { auth: { persistSession: false } });
|
|
@@ -41,5 +40,4 @@ module.exports = async () => {
|
|
|
41
40
|
catch (err) { console.log('Redis Failed', err); return; }
|
|
42
41
|
|
|
43
42
|
global.redis = redis;
|
|
44
|
-
global.redisLock = redisLock(redis);
|
|
45
43
|
};
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const crypto = require('crypto');
|
|
4
|
-
|
|
5
|
-
const DEFAULT_TIMEOUT = 5_000;
|
|
6
|
-
const DEFAULT_RETRY_DELAY = 50;
|
|
7
|
-
const DEFAULT_WAIT_TIMEOUT = 30_000;
|
|
8
|
-
|
|
9
|
-
// Atomic compare-and-delete so we only release a lock we still hold.
|
|
10
|
-
// Without this, an expired lock that another caller already re-acquired
|
|
11
|
-
// would be deleted by our release(), letting a third caller acquire it
|
|
12
|
-
// while the second is still inside its critical section.
|
|
13
|
-
const RELEASE_SCRIPT = 'if redis.call("GET", KEYS[1]) == ARGV[1] then return redis.call("DEL", KEYS[1]) else return 0 end';
|
|
14
|
-
|
|
15
|
-
function redisLock(client, retryDelay = DEFAULT_RETRY_DELAY) {
|
|
16
|
-
async function lock(lockName, timeout = DEFAULT_TIMEOUT, waitTimeout = DEFAULT_WAIT_TIMEOUT) {
|
|
17
|
-
const lockKey = `lock.${lockName}`;
|
|
18
|
-
const token = crypto.randomBytes(16).toString('hex');
|
|
19
|
-
const deadline = Date.now() + waitTimeout;
|
|
20
|
-
let released = false;
|
|
21
|
-
|
|
22
|
-
while (true) {
|
|
23
|
-
const result = await client.set(lockKey, token, { PX: timeout, NX: true });
|
|
24
|
-
if (result !== null) {
|
|
25
|
-
return async () => {
|
|
26
|
-
if (released) return;
|
|
27
|
-
released = true;
|
|
28
|
-
try { await client.sendCommand(['EVAL', RELEASE_SCRIPT, '1', lockKey, token]); }
|
|
29
|
-
catch {}
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
if (Date.now() >= deadline) throw new Error(`redisLock: timed out waiting for "${lockName}" after ${waitTimeout}ms`);
|
|
33
|
-
await new Promise(r => setTimeout(r, retryDelay));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return lock;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
module.exports = redisLock;
|