@rpcbase/cli 0.192.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/cli",
3
- "version": "0.192.0",
3
+ "version": "0.193.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src"
@@ -284,12 +284,50 @@ export const deploy = async (argv) => {
284
284
  await ssh(`cd ~/apps/${baseDeployDir}/infrastructure && RB_DEPLOY_DIR=${shellQuote(baseDeployDir)} node ctrl.js ${action}-instance ${instance} prod`, true)
285
285
  }
286
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
+
287
309
  const waitForInstance = async (instance, target) => {
288
310
  const port = Number(target?.port)
289
311
  if (!Number.isFinite(port) || port <= 0) throw new Error(`Cannot healthcheck instance ${instance}: invalid port`)
290
312
 
291
- const url = `http://127.0.0.1:${port}/`
292
- const healthcheckScript = `fetch(${JSON.stringify(url)}).then((res) => process.exit(res.status < 500 ? 0 : 1)).catch(() => process.exit(1))`
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(";")
293
331
  for (let attempt = 1; attempt <= 60; attempt += 1) {
294
332
  try {
295
333
  await ssh(`node -e ${shellQuote(healthcheckScript)}`)
@@ -300,6 +338,7 @@ export const deploy = async (argv) => {
300
338
  }
301
339
  }
302
340
 
341
+ await printInstanceDiagnostics(instance)
303
342
  throw new Error(`Instance ${instance} did not become healthy at ${url}`)
304
343
  }
305
344