@rpcbase/cli 0.191.0 → 0.193.0
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/cmd-deploy/index.js +50 -5
- package/src/cmd-ssh.js +9 -3
package/package.json
CHANGED
package/src/cmd-deploy/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execSync } from "child_process"
|
|
1
|
+
import { execFileSync, execSync } from "child_process"
|
|
2
2
|
import fs from "fs"
|
|
3
3
|
import os from "os"
|
|
4
4
|
import path from "path"
|
|
@@ -246,9 +246,15 @@ export const deploy = async (argv) => {
|
|
|
246
246
|
let preparedDeploy = null
|
|
247
247
|
|
|
248
248
|
const ssh = async (command, stdioInherit = false) => {
|
|
249
|
-
const sshCommand = `ssh -i "${keyPath}" -o StrictHostKeyChecking=no ${user}@${host} "${command}"`
|
|
250
249
|
log(`${command}`)
|
|
251
|
-
const out =
|
|
250
|
+
const out = execFileSync("ssh", [
|
|
251
|
+
"-i",
|
|
252
|
+
keyPath,
|
|
253
|
+
"-o",
|
|
254
|
+
"StrictHostKeyChecking=no",
|
|
255
|
+
`${user}@${host}`,
|
|
256
|
+
command,
|
|
257
|
+
], {
|
|
252
258
|
stdio: (argv.verbose || stdioInherit) ? "inherit" : "pipe",
|
|
253
259
|
})
|
|
254
260
|
const res = out?.toString()?.trim() || ""
|
|
@@ -278,12 +284,50 @@ export const deploy = async (argv) => {
|
|
|
278
284
|
await ssh(`cd ~/apps/${baseDeployDir}/infrastructure && RB_DEPLOY_DIR=${shellQuote(baseDeployDir)} node ctrl.js ${action}-instance ${instance} prod`, true)
|
|
279
285
|
}
|
|
280
286
|
|
|
287
|
+
const printInstanceDiagnostics = async (instance) => {
|
|
288
|
+
const composePrefix = [
|
|
289
|
+
`cd ~/apps/${baseDeployDir}/infrastructure &&`,
|
|
290
|
+
`RB_DEPLOY_DIR=${shellQuote(baseDeployDir)}`,
|
|
291
|
+
"docker compose -p sample-app --env-file ../.env -f compose.yml -f compose.instances.yml",
|
|
292
|
+
`--profile instance-${instance}`,
|
|
293
|
+
].join(" ")
|
|
294
|
+
const services = `server-${instance} worker-${instance}`
|
|
295
|
+
|
|
296
|
+
console.error(`Instance ${instance} diagnostics:`)
|
|
297
|
+
for (const command of [
|
|
298
|
+
`${composePrefix} ps ${services}`,
|
|
299
|
+
`${composePrefix} logs --tail=160 ${services}`,
|
|
300
|
+
]) {
|
|
301
|
+
try {
|
|
302
|
+
await ssh(command, true)
|
|
303
|
+
} catch (error) {
|
|
304
|
+
console.error(`Failed to run diagnostics command: ${error instanceof Error ? error.message : error}`)
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
281
309
|
const waitForInstance = async (instance, target) => {
|
|
282
310
|
const port = Number(target?.port)
|
|
283
311
|
if (!Number.isFinite(port) || port <= 0) throw new Error(`Cannot healthcheck instance ${instance}: invalid port`)
|
|
284
312
|
|
|
285
|
-
const
|
|
286
|
-
const
|
|
313
|
+
const healthPath = typeof target?.healthPath === "string" && target.healthPath.startsWith("/") ? target.healthPath : "/_healthcheck"
|
|
314
|
+
const url = `http://127.0.0.1:${port}${healthPath}`
|
|
315
|
+
const healthcheckScript = [
|
|
316
|
+
`const url = ${JSON.stringify(url)}`,
|
|
317
|
+
"const controller = new AbortController()",
|
|
318
|
+
"const timeout = setTimeout(() => controller.abort(), 2000)",
|
|
319
|
+
"fetch(url, { signal: controller.signal }).then(async (res) => {",
|
|
320
|
+
" clearTimeout(timeout)",
|
|
321
|
+
" if (res.status < 500) process.exit(0)",
|
|
322
|
+
" const body = await res.text().catch(() => '')",
|
|
323
|
+
" console.error(`healthcheck ${url} failed with status ${res.status}: ${body.slice(0, 500)}`)",
|
|
324
|
+
" process.exit(1)",
|
|
325
|
+
"}).catch((error) => {",
|
|
326
|
+
" clearTimeout(timeout)",
|
|
327
|
+
" console.error(`healthcheck ${url} failed: ${error?.code || error?.name || 'Error'} ${error?.message || error}`)",
|
|
328
|
+
" process.exit(1)",
|
|
329
|
+
"})",
|
|
330
|
+
].join(";")
|
|
287
331
|
for (let attempt = 1; attempt <= 60; attempt += 1) {
|
|
288
332
|
try {
|
|
289
333
|
await ssh(`node -e ${shellQuote(healthcheckScript)}`)
|
|
@@ -294,6 +338,7 @@ export const deploy = async (argv) => {
|
|
|
294
338
|
}
|
|
295
339
|
}
|
|
296
340
|
|
|
341
|
+
await printInstanceDiagnostics(instance)
|
|
297
342
|
throw new Error(`Instance ${instance} did not become healthy at ${url}`)
|
|
298
343
|
}
|
|
299
344
|
|
package/src/cmd-ssh.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFileSync } from "child_process"
|
|
2
2
|
import fs from "fs"
|
|
3
3
|
import path from "path"
|
|
4
4
|
import os from "os"
|
|
@@ -45,9 +45,15 @@ export const ssh = async (argv) => {
|
|
|
45
45
|
let tempKeyPath = null
|
|
46
46
|
|
|
47
47
|
const execSsh = async (command, stdioInherit = true) => {
|
|
48
|
-
const sshCommand = `ssh -i "${keyPath}" -o StrictHostKeyChecking=no ${user}@${host} "${command}"`
|
|
49
48
|
log(`${command}`)
|
|
50
|
-
const out =
|
|
49
|
+
const out = execFileSync("ssh", [
|
|
50
|
+
"-i",
|
|
51
|
+
keyPath,
|
|
52
|
+
"-o",
|
|
53
|
+
"StrictHostKeyChecking=no",
|
|
54
|
+
`${user}@${host}`,
|
|
55
|
+
command,
|
|
56
|
+
], {
|
|
51
57
|
stdio: (argv.verbose || stdioInherit) ? "inherit" : "pipe",
|
|
52
58
|
})
|
|
53
59
|
const res = out?.toString()?.trim() || ""
|