@qodalis/cli-server-jobs 2.0.0-beta.16 → 2.0.0-beta.18
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 +2 -2
- package/public-api.d.mts +18 -2
- package/public-api.d.ts +18 -2
- package/public-api.js +454 -253
- package/public-api.js.map +1 -1
- package/public-api.mjs +455 -254
- package/public-api.mjs.map +1 -1
- package/umd/index.global.js +712 -319
package/public-api.js
CHANGED
|
@@ -117,10 +117,41 @@ async function resolveJobId(service, nameOrId) {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
const jobs = await service.listJobs();
|
|
120
|
-
const
|
|
121
|
-
|
|
120
|
+
const lower = nameOrId.toLowerCase();
|
|
121
|
+
return jobs.find((j) => j.id === nameOrId) ?? jobs.find((j) => j.name === nameOrId) ?? jobs.find((j) => j.name.toLowerCase() === lower) ?? null;
|
|
122
|
+
}
|
|
123
|
+
async function findJobOnServers(context, services, nameOrId) {
|
|
124
|
+
const matches = [];
|
|
125
|
+
const missing = [];
|
|
126
|
+
for (const { name, service } of services) {
|
|
127
|
+
try {
|
|
128
|
+
const job = await resolveJobId(service, nameOrId);
|
|
129
|
+
if (job) {
|
|
130
|
+
matches.push({ name, service, job });
|
|
131
|
+
} else {
|
|
132
|
+
missing.push(name);
|
|
133
|
+
}
|
|
134
|
+
} catch (e) {
|
|
135
|
+
context.writer.writeError(`Error on server ${name}: ${e.message}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (matches.length === 0 && missing.length > 0) {
|
|
139
|
+
if (missing.length === services.length) {
|
|
140
|
+
context.writer.writeError(
|
|
141
|
+
services.length === 1 ? `Job "${nameOrId}" not found on server ${missing[0]}.` : `Job "${nameOrId}" not found on any of the ${services.length} connected servers.`
|
|
142
|
+
);
|
|
143
|
+
} else {
|
|
144
|
+
context.writer.writeError(
|
|
145
|
+
`Job "${nameOrId}" not found on ${missing.length === 1 ? "server" : "servers"} ${missing.join(", ")}.`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return matches;
|
|
150
|
+
}
|
|
151
|
+
function writeServerHeader(context, name) {
|
|
152
|
+
context.writer.writeln(
|
|
153
|
+
context.writer.wrapInColor(`Server: ${name}`, cliCore.CliForegroundColor.Cyan)
|
|
122
154
|
);
|
|
123
|
-
return match ?? null;
|
|
124
155
|
}
|
|
125
156
|
function formatRelativeTime(isoString) {
|
|
126
157
|
if (!isoString) return "-";
|
|
@@ -195,6 +226,26 @@ var CliJobsCommandProcessor = class {
|
|
|
195
226
|
command: "jobs",
|
|
196
227
|
description: "Manage background jobs on connected servers",
|
|
197
228
|
author: cliCore.DefaultLibraryAuthor,
|
|
229
|
+
writeDescription: (context) => {
|
|
230
|
+
const t = context.translator;
|
|
231
|
+
cliCore.writeWrapped(
|
|
232
|
+
context,
|
|
233
|
+
t.t("cli.server.jobs.help.see_control_background_jobs", "See and control the background jobs that run on connected servers: list them, run one now, pause or stop it, read its history and logs, change its settings, or watch events live. A job is picked by name (any case) or ID and looked up on every connected server; actions apply to each server that has the job, and --server limits a command to one server.")
|
|
234
|
+
);
|
|
235
|
+
context.writer.writeln();
|
|
236
|
+
cliCore.writeUsage(context, [
|
|
237
|
+
["server jobs", t.t("cli.server.jobs.help.same_server_jobs_list", "Same as server jobs list")],
|
|
238
|
+
["server jobs <action> <name|id>", "info, trigger, pause, resume, stop, cancel, history, logs, edit"],
|
|
239
|
+
["server jobs watch", t.t("cli.server.jobs.help.live_job_events", "Live job events")]
|
|
240
|
+
]);
|
|
241
|
+
context.writer.writeln();
|
|
242
|
+
cliCore.writeExamples(context, [
|
|
243
|
+
["server jobs", t.t("cli.server.jobs.help.all_jobs", "All jobs")],
|
|
244
|
+
["server jobs trigger cleanup", t.t("cli.server.jobs.help.run_cleanup_job_now", "Run the cleanup job now")],
|
|
245
|
+
["server jobs history cleanup --status failed", t.t("cli.server.jobs.help.failed_runs", "Its failed runs")],
|
|
246
|
+
["server jobs logs cleanup --server node", t.t("cli.server.jobs.help.last_run_output_node", "Last run output, on node")]
|
|
247
|
+
]);
|
|
248
|
+
},
|
|
198
249
|
metadata: {
|
|
199
250
|
icon: cliCore.CliIcon.Gear,
|
|
200
251
|
module: "@qodalis/cli-server-jobs"
|
|
@@ -205,6 +256,23 @@ var CliJobsCommandProcessor = class {
|
|
|
205
256
|
{
|
|
206
257
|
command: "list",
|
|
207
258
|
description: "List all jobs across connected servers",
|
|
259
|
+
writeDescription: (context) => {
|
|
260
|
+
const t = context.translator;
|
|
261
|
+
cliCore.writeWrapped(
|
|
262
|
+
context,
|
|
263
|
+
t.t("cli.server.jobs.list.help.list_jobs_every_connected", "List the jobs of every connected server: group, status, schedule, last and next run, and how long the last run took. With several servers, each gets its own table.")
|
|
264
|
+
);
|
|
265
|
+
context.writer.writeln();
|
|
266
|
+
cliCore.writeUsage(context, [
|
|
267
|
+
["server jobs list", t.t("cli.server.jobs.list.help.jobs_all_connected_servers", "Jobs on all connected servers")],
|
|
268
|
+
["server jobs ls --group <name>", t.t("cli.server.jobs.list.help.only_one_group", "Only one group")]
|
|
269
|
+
]);
|
|
270
|
+
context.writer.writeln();
|
|
271
|
+
cliCore.writeExamples(context, [
|
|
272
|
+
["server jobs ls --server node", t.t("cli.server.jobs.list.help.jobs_node_server", "Jobs on the node server")],
|
|
273
|
+
["server jobs list --group reports", t.t("cli.server.jobs.list.help.jobs_reports_group", "Jobs in the reports group")]
|
|
274
|
+
]);
|
|
275
|
+
},
|
|
208
276
|
aliases: ["ls"],
|
|
209
277
|
parameters: [
|
|
210
278
|
serverParam,
|
|
@@ -223,6 +291,21 @@ var CliJobsCommandProcessor = class {
|
|
|
223
291
|
{
|
|
224
292
|
command: "info",
|
|
225
293
|
description: "Show detailed information about a job",
|
|
294
|
+
writeDescription: (context) => {
|
|
295
|
+
const t = context.translator;
|
|
296
|
+
cliCore.writeWrapped(
|
|
297
|
+
context,
|
|
298
|
+
t.t("cli.server.jobs.info.help.show_everything_about_one", "Show everything about one job: schedule, retries, timeout, overlap policy, the execution running now and the result of the last run. The job is found by name (any case) or ID.")
|
|
299
|
+
);
|
|
300
|
+
context.writer.writeln();
|
|
301
|
+
cliCore.writeUsage(context, [
|
|
302
|
+
["server jobs info <name|id>", ""]
|
|
303
|
+
]);
|
|
304
|
+
context.writer.writeln();
|
|
305
|
+
cliCore.writeExamples(context, [
|
|
306
|
+
["server jobs info cleanup", t.t("cli.server.jobs.info.help.details_cleanup_job", "Details of the cleanup job")]
|
|
307
|
+
]);
|
|
308
|
+
},
|
|
226
309
|
valueRequired: true,
|
|
227
310
|
parameters: [serverParam],
|
|
228
311
|
processCommand: async (cmd, context) => {
|
|
@@ -233,6 +316,22 @@ var CliJobsCommandProcessor = class {
|
|
|
233
316
|
{
|
|
234
317
|
command: "trigger",
|
|
235
318
|
description: "Trigger immediate execution of a job",
|
|
319
|
+
writeDescription: (context) => {
|
|
320
|
+
const t = context.translator;
|
|
321
|
+
cliCore.writeWrapped(
|
|
322
|
+
context,
|
|
323
|
+
t.t("cli.server.jobs.trigger.help.run_job_now_without", "Run a job now, without waiting for its next scheduled time. Its schedule does not change.")
|
|
324
|
+
);
|
|
325
|
+
context.writer.writeln();
|
|
326
|
+
cliCore.writeUsage(context, [
|
|
327
|
+
["server jobs trigger <name|id>", ""]
|
|
328
|
+
]);
|
|
329
|
+
context.writer.writeln();
|
|
330
|
+
cliCore.writeExamples(context, [
|
|
331
|
+
["server jobs trigger cleanup", t.t("cli.server.jobs.trigger.help.run_cleanup_now", "Run cleanup now")],
|
|
332
|
+
["server jobs logs cleanup", t.t("cli.server.jobs.trigger.help.then_read_output", "Then read its output")]
|
|
333
|
+
]);
|
|
334
|
+
},
|
|
236
335
|
valueRequired: true,
|
|
237
336
|
parameters: [serverParam],
|
|
238
337
|
processCommand: async (cmd, context) => {
|
|
@@ -243,6 +342,22 @@ var CliJobsCommandProcessor = class {
|
|
|
243
342
|
{
|
|
244
343
|
command: "pause",
|
|
245
344
|
description: "Pause scheduled execution of a job",
|
|
345
|
+
writeDescription: (context) => {
|
|
346
|
+
const t = context.translator;
|
|
347
|
+
cliCore.writeWrapped(
|
|
348
|
+
context,
|
|
349
|
+
t.t("cli.server.jobs.pause.help.stop_running_job_schedule", "Stop running a job on its schedule until it is resumed. Use cancel or stop for a run that is already in progress.")
|
|
350
|
+
);
|
|
351
|
+
context.writer.writeln();
|
|
352
|
+
cliCore.writeUsage(context, [
|
|
353
|
+
["server jobs pause <name|id>", ""]
|
|
354
|
+
]);
|
|
355
|
+
context.writer.writeln();
|
|
356
|
+
cliCore.writeExamples(context, [
|
|
357
|
+
["server jobs pause cleanup", t.t("cli.server.jobs.pause.help.hold_cleanup", "Hold cleanup")],
|
|
358
|
+
["server jobs resume cleanup", t.t("cli.server.jobs.pause.help.put_back_schedule", "Put it back on schedule")]
|
|
359
|
+
]);
|
|
360
|
+
},
|
|
246
361
|
valueRequired: true,
|
|
247
362
|
parameters: [serverParam],
|
|
248
363
|
processCommand: async (cmd, context) => {
|
|
@@ -253,6 +368,21 @@ var CliJobsCommandProcessor = class {
|
|
|
253
368
|
{
|
|
254
369
|
command: "resume",
|
|
255
370
|
description: "Resume a paused job",
|
|
371
|
+
writeDescription: (context) => {
|
|
372
|
+
const t = context.translator;
|
|
373
|
+
cliCore.writeWrapped(
|
|
374
|
+
context,
|
|
375
|
+
t.t("cli.server.jobs.resume.help.put_paused_job_back", "Put a paused job back on its schedule.")
|
|
376
|
+
);
|
|
377
|
+
context.writer.writeln();
|
|
378
|
+
cliCore.writeUsage(context, [
|
|
379
|
+
["server jobs resume <name|id>", ""]
|
|
380
|
+
]);
|
|
381
|
+
context.writer.writeln();
|
|
382
|
+
cliCore.writeExamples(context, [
|
|
383
|
+
["server jobs resume cleanup", t.t("cli.server.jobs.resume.help.run_cleanup_schedule_again", "Run cleanup on schedule again")]
|
|
384
|
+
]);
|
|
385
|
+
},
|
|
256
386
|
valueRequired: true,
|
|
257
387
|
parameters: [serverParam],
|
|
258
388
|
processCommand: async (cmd, context) => {
|
|
@@ -263,6 +393,21 @@ var CliJobsCommandProcessor = class {
|
|
|
263
393
|
{
|
|
264
394
|
command: "stop",
|
|
265
395
|
description: "Stop a job and cancel current execution if running",
|
|
396
|
+
writeDescription: (context) => {
|
|
397
|
+
const t = context.translator;
|
|
398
|
+
cliCore.writeWrapped(
|
|
399
|
+
context,
|
|
400
|
+
t.t("cli.server.jobs.stop.help.take_job_off_schedule", "Take a job off its schedule and cancel the run in progress, if there is one.")
|
|
401
|
+
);
|
|
402
|
+
context.writer.writeln();
|
|
403
|
+
cliCore.writeUsage(context, [
|
|
404
|
+
["server jobs stop <name|id>", ""]
|
|
405
|
+
]);
|
|
406
|
+
context.writer.writeln();
|
|
407
|
+
cliCore.writeExamples(context, [
|
|
408
|
+
["server jobs stop cleanup", t.t("cli.server.jobs.stop.help.stop_cleanup_completely", "Stop cleanup completely")]
|
|
409
|
+
]);
|
|
410
|
+
},
|
|
266
411
|
valueRequired: true,
|
|
267
412
|
parameters: [serverParam],
|
|
268
413
|
processCommand: async (cmd, context) => {
|
|
@@ -273,6 +418,21 @@ var CliJobsCommandProcessor = class {
|
|
|
273
418
|
{
|
|
274
419
|
command: "cancel",
|
|
275
420
|
description: "Cancel the current execution of a job",
|
|
421
|
+
writeDescription: (context) => {
|
|
422
|
+
const t = context.translator;
|
|
423
|
+
cliCore.writeWrapped(
|
|
424
|
+
context,
|
|
425
|
+
t.t("cli.server.jobs.cancel.help.cancel_run_progress_job", "Cancel the run in progress of a job. The job stays on its schedule and runs again at the next time.")
|
|
426
|
+
);
|
|
427
|
+
context.writer.writeln();
|
|
428
|
+
cliCore.writeUsage(context, [
|
|
429
|
+
["server jobs cancel <name|id>", ""]
|
|
430
|
+
]);
|
|
431
|
+
context.writer.writeln();
|
|
432
|
+
cliCore.writeExamples(context, [
|
|
433
|
+
["server jobs cancel cleanup", t.t("cli.server.jobs.cancel.help.abort_current_cleanup_run", "Abort the current cleanup run")]
|
|
434
|
+
]);
|
|
435
|
+
},
|
|
276
436
|
valueRequired: true,
|
|
277
437
|
parameters: [serverParam],
|
|
278
438
|
processCommand: async (cmd, context) => {
|
|
@@ -283,6 +443,23 @@ var CliJobsCommandProcessor = class {
|
|
|
283
443
|
{
|
|
284
444
|
command: "history",
|
|
285
445
|
description: "Show execution history for a job",
|
|
446
|
+
writeDescription: (context) => {
|
|
447
|
+
const t = context.translator;
|
|
448
|
+
cliCore.writeWrapped(
|
|
449
|
+
context,
|
|
450
|
+
t.t("cli.server.jobs.history.help.list_past_runs_job", "List the past runs of a job: status, start time, duration, retry attempt and the start of the error message. Use the short ID with logs --exec to read the output of one run.")
|
|
451
|
+
);
|
|
452
|
+
context.writer.writeln();
|
|
453
|
+
cliCore.writeUsage(context, [
|
|
454
|
+
["server jobs history <name|id>", t.t("cli.server.jobs.history.help.last_20_runs", "The last 20 runs")],
|
|
455
|
+
["server jobs history <name|id> --limit <n> --offset <n>", t.t("cli.server.jobs.history.help.page_through_older_runs", "Page through older runs")]
|
|
456
|
+
]);
|
|
457
|
+
context.writer.writeln();
|
|
458
|
+
cliCore.writeExamples(context, [
|
|
459
|
+
["server jobs history cleanup --status failed", t.t("cli.server.jobs.history.help.only_failed_runs", "Only failed runs")],
|
|
460
|
+
["server jobs history cleanup --limit 5", t.t("cli.server.jobs.history.help.last_5_runs", "The last 5 runs")]
|
|
461
|
+
]);
|
|
462
|
+
},
|
|
286
463
|
valueRequired: true,
|
|
287
464
|
parameters: [
|
|
288
465
|
serverParam,
|
|
@@ -315,6 +492,22 @@ var CliJobsCommandProcessor = class {
|
|
|
315
492
|
{
|
|
316
493
|
command: "logs",
|
|
317
494
|
description: "Show logs from the latest or a specific execution",
|
|
495
|
+
writeDescription: (context) => {
|
|
496
|
+
const t = context.translator;
|
|
497
|
+
cliCore.writeWrapped(
|
|
498
|
+
context,
|
|
499
|
+
t.t("cli.server.jobs.logs.help.print_log_entries_latest", "Print the log entries of the latest run of a job, or of one run picked by its execution ID (from history).")
|
|
500
|
+
);
|
|
501
|
+
context.writer.writeln();
|
|
502
|
+
cliCore.writeUsage(context, [
|
|
503
|
+
["server jobs logs <name|id>", t.t("cli.server.jobs.logs.help.logs_latest_run", "Logs of the latest run")],
|
|
504
|
+
["server jobs logs <name|id> --exec <id>", t.t("cli.server.jobs.logs.help.logs_one_run", "Logs of one run")]
|
|
505
|
+
]);
|
|
506
|
+
context.writer.writeln();
|
|
507
|
+
cliCore.writeExamples(context, [
|
|
508
|
+
["server jobs logs cleanup", t.t("cli.server.jobs.logs.help.what_last_cleanup_run", "What the last cleanup run printed")]
|
|
509
|
+
]);
|
|
510
|
+
},
|
|
318
511
|
valueRequired: true,
|
|
319
512
|
parameters: [
|
|
320
513
|
serverParam,
|
|
@@ -333,6 +526,21 @@ var CliJobsCommandProcessor = class {
|
|
|
333
526
|
{
|
|
334
527
|
command: "edit",
|
|
335
528
|
description: "Interactively edit job settings",
|
|
529
|
+
writeDescription: (context) => {
|
|
530
|
+
const t = context.translator;
|
|
531
|
+
cliCore.writeWrapped(
|
|
532
|
+
context,
|
|
533
|
+
t.t("cli.server.jobs.edit.help.change_job_step_step", "Change a job step by step: description, group, cron schedule or interval, max retries, timeout and overlap policy (skip, queue or cancel). Press Enter to keep a value and Ctrl+C or Escape to cancel; nothing changes until you confirm. A job on several servers needs --server.")
|
|
534
|
+
);
|
|
535
|
+
context.writer.writeln();
|
|
536
|
+
cliCore.writeUsage(context, [
|
|
537
|
+
["server jobs edit <name|id>", ""]
|
|
538
|
+
]);
|
|
539
|
+
context.writer.writeln();
|
|
540
|
+
cliCore.writeExamples(context, [
|
|
541
|
+
["server jobs edit cleanup", t.t("cli.server.jobs.edit.help.edit_cleanup_server_has", "Edit cleanup on the server that has it")]
|
|
542
|
+
]);
|
|
543
|
+
},
|
|
336
544
|
valueRequired: true,
|
|
337
545
|
parameters: [serverParam],
|
|
338
546
|
processCommand: async (cmd, context) => {
|
|
@@ -343,6 +551,21 @@ var CliJobsCommandProcessor = class {
|
|
|
343
551
|
{
|
|
344
552
|
command: "watch",
|
|
345
553
|
description: "Live view of job events via WebSocket",
|
|
554
|
+
writeDescription: (context) => {
|
|
555
|
+
const t = context.translator;
|
|
556
|
+
cliCore.writeWrapped(
|
|
557
|
+
context,
|
|
558
|
+
t.t("cli.server.jobs.watch.help.follow_job_events_they", "Follow job events as they happen (started, completed, failed and so on) on every connected server, one line per event. Press Ctrl+C to stop.")
|
|
559
|
+
);
|
|
560
|
+
context.writer.writeln();
|
|
561
|
+
cliCore.writeUsage(context, [
|
|
562
|
+
["server jobs watch", t.t("cli.server.jobs.watch.help.events_all_connected_servers", "Events from all connected servers")]
|
|
563
|
+
]);
|
|
564
|
+
context.writer.writeln();
|
|
565
|
+
cliCore.writeExamples(context, [
|
|
566
|
+
["server jobs watch --server node", t.t("cli.server.jobs.watch.help.only_events_node", "Only events from node")]
|
|
567
|
+
]);
|
|
568
|
+
},
|
|
346
569
|
parameters: [serverParam],
|
|
347
570
|
processCommand: async (cmd, context) => {
|
|
348
571
|
await this.handleWatch(cmd, context);
|
|
@@ -416,9 +639,9 @@ var CliJobsCommandProcessor = class {
|
|
|
416
639
|
}
|
|
417
640
|
// ── Info ──────────────────────────────────────────────────────────
|
|
418
641
|
async handleInfo(cmd, context) {
|
|
419
|
-
const nameOrId = (cmd.value ?? "")
|
|
642
|
+
const nameOrId = cliCore.joinShellWords(cmd.value ?? "");
|
|
420
643
|
if (!nameOrId) {
|
|
421
|
-
context.writer.writeError("Usage: jobs info <id|name>");
|
|
644
|
+
context.writer.writeError("Usage: server jobs info <id|name>");
|
|
422
645
|
return;
|
|
423
646
|
}
|
|
424
647
|
const services = getServices(context, cmd.args);
|
|
@@ -426,74 +649,53 @@ var CliJobsCommandProcessor = class {
|
|
|
426
649
|
context.writer.writeInfo("No connected servers.");
|
|
427
650
|
return;
|
|
428
651
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
],
|
|
463
|
-
["Overlap Policy", job.overlapPolicy],
|
|
464
|
-
[
|
|
465
|
-
"Current Execution",
|
|
466
|
-
job.currentExecutionId ?? "none"
|
|
467
|
-
],
|
|
468
|
-
["Next Run", formatRelativeTime(job.nextRunAt)],
|
|
469
|
-
["Last Run", formatRelativeTime(job.lastRunAt)],
|
|
470
|
-
[
|
|
471
|
-
"Last Run Status",
|
|
472
|
-
job.lastRunStatus ? statusColor(job.lastRunStatus, context.writer) : "-"
|
|
473
|
-
],
|
|
474
|
-
["Last Run Duration", formatDuration(job.lastRunDuration)]
|
|
475
|
-
];
|
|
476
|
-
for (const [label, value] of lines) {
|
|
477
|
-
context.writer.writeln(
|
|
478
|
-
` ${context.writer.wrapInColor(
|
|
479
|
-
label.padEnd(20),
|
|
480
|
-
cliCore.CliForegroundColor.Yellow
|
|
481
|
-
)} ${value}`
|
|
482
|
-
);
|
|
483
|
-
}
|
|
484
|
-
return;
|
|
485
|
-
} catch (e) {
|
|
486
|
-
context.writer.writeError(
|
|
487
|
-
`Error on server ${name}: ${e.message}`
|
|
652
|
+
const matches = await findJobOnServers(context, services, nameOrId);
|
|
653
|
+
for (const { name, job } of matches) {
|
|
654
|
+
if (services.length > 1) {
|
|
655
|
+
writeServerHeader(context, name);
|
|
656
|
+
}
|
|
657
|
+
const lines = [
|
|
658
|
+
["ID", job.id],
|
|
659
|
+
["Name", job.name],
|
|
660
|
+
["Description", job.description],
|
|
661
|
+
["Group", job.group ?? "-"],
|
|
662
|
+
["Status", statusColor(job.status, context.writer)],
|
|
663
|
+
[
|
|
664
|
+
"Schedule",
|
|
665
|
+
job.schedule ?? (job.interval ? `every ${job.interval}ms` : "-")
|
|
666
|
+
],
|
|
667
|
+
["Max Retries", String(job.maxRetries)],
|
|
668
|
+
["Timeout", job.timeout ? `${job.timeout}ms` : "none"],
|
|
669
|
+
["Overlap Policy", job.overlapPolicy],
|
|
670
|
+
["Current Execution", job.currentExecutionId ?? "none"],
|
|
671
|
+
["Next Run", formatRelativeTime(job.nextRunAt)],
|
|
672
|
+
["Last Run", formatRelativeTime(job.lastRunAt)],
|
|
673
|
+
[
|
|
674
|
+
"Last Run Status",
|
|
675
|
+
job.lastRunStatus ? statusColor(job.lastRunStatus, context.writer) : "-"
|
|
676
|
+
],
|
|
677
|
+
["Last Run Duration", formatDuration(job.lastRunDuration)]
|
|
678
|
+
];
|
|
679
|
+
for (const [label, value] of lines) {
|
|
680
|
+
context.writer.writeln(
|
|
681
|
+
` ${context.writer.wrapInColor(
|
|
682
|
+
label.padEnd(20),
|
|
683
|
+
cliCore.CliForegroundColor.Yellow
|
|
684
|
+
)} ${value}`
|
|
488
685
|
);
|
|
489
686
|
}
|
|
490
687
|
}
|
|
491
688
|
}
|
|
492
689
|
// ── Action (trigger/pause/resume/stop/cancel) ────────────────────
|
|
690
|
+
/**
|
|
691
|
+
* Without --server the action applies to every connected server that has
|
|
692
|
+
* the job, each reported on its own line. When several servers have it,
|
|
693
|
+
* a note says so (and how to target one).
|
|
694
|
+
*/
|
|
493
695
|
async handleAction(cmd, context, action) {
|
|
494
|
-
const nameOrId = (cmd.value ?? "")
|
|
696
|
+
const nameOrId = cliCore.joinShellWords(cmd.value ?? "");
|
|
495
697
|
if (!nameOrId) {
|
|
496
|
-
context.writer.writeError(`Usage: jobs ${action} <id|name>`);
|
|
698
|
+
context.writer.writeError(`Usage: server jobs ${action} <id|name>`);
|
|
497
699
|
return;
|
|
498
700
|
}
|
|
499
701
|
const services = getServices(context, cmd.args);
|
|
@@ -501,17 +703,14 @@ var CliJobsCommandProcessor = class {
|
|
|
501
703
|
context.writer.writeInfo("No connected servers.");
|
|
502
704
|
return;
|
|
503
705
|
}
|
|
504
|
-
|
|
706
|
+
const matches = await findJobOnServers(context, services, nameOrId);
|
|
707
|
+
if (matches.length > 1) {
|
|
708
|
+
context.writer.writeInfo(
|
|
709
|
+
`Job "${nameOrId}" is on ${matches.length} servers (${matches.map((m) => m.name).join(", ")}); applying ${action} to each. Use --server <name> to target one.`
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
for (const { name, service, job } of matches) {
|
|
505
713
|
try {
|
|
506
|
-
const job = await resolveJobId(service, nameOrId);
|
|
507
|
-
if (!job) {
|
|
508
|
-
if (services.length === 1) {
|
|
509
|
-
context.writer.writeError(
|
|
510
|
-
`Job "${nameOrId}" not found on server ${name}.`
|
|
511
|
-
);
|
|
512
|
-
}
|
|
513
|
-
continue;
|
|
514
|
-
}
|
|
515
714
|
switch (action) {
|
|
516
715
|
case "trigger":
|
|
517
716
|
await service.triggerJob(job.id);
|
|
@@ -531,9 +730,8 @@ var CliJobsCommandProcessor = class {
|
|
|
531
730
|
}
|
|
532
731
|
const serverSuffix = services.length > 1 ? ` on server ${name}` : "";
|
|
533
732
|
context.writer.writeSuccess(
|
|
534
|
-
`Job "${job.name}" ${action
|
|
733
|
+
`Job "${job.name}" ${PAST_TENSE[action] ?? `${action}ed`}${serverSuffix}.`
|
|
535
734
|
);
|
|
536
|
-
return;
|
|
537
735
|
} catch (e) {
|
|
538
736
|
context.writer.writeError(
|
|
539
737
|
`Failed to ${action} job on ${name}: ${e.message}`
|
|
@@ -543,9 +741,9 @@ var CliJobsCommandProcessor = class {
|
|
|
543
741
|
}
|
|
544
742
|
// ── History ──────────────────────────────────────────────────────
|
|
545
743
|
async handleHistory(cmd, context) {
|
|
546
|
-
const nameOrId = (cmd.value ?? "")
|
|
744
|
+
const nameOrId = cliCore.joinShellWords(cmd.value ?? "");
|
|
547
745
|
if (!nameOrId) {
|
|
548
|
-
context.writer.writeError("Usage: jobs history <id|name>");
|
|
746
|
+
context.writer.writeError("Usage: server jobs history <id|name>");
|
|
549
747
|
return;
|
|
550
748
|
}
|
|
551
749
|
const services = getServices(context, cmd.args);
|
|
@@ -556,24 +754,11 @@ var CliJobsCommandProcessor = class {
|
|
|
556
754
|
const limit = cmd.args["limit"] ?? 20;
|
|
557
755
|
const offset = cmd.args["offset"] ?? 0;
|
|
558
756
|
const status = cmd.args["status"];
|
|
559
|
-
|
|
757
|
+
const matches = await findJobOnServers(context, services, nameOrId);
|
|
758
|
+
for (const { name, service, job } of matches) {
|
|
560
759
|
try {
|
|
561
|
-
const job = await resolveJobId(service, nameOrId);
|
|
562
|
-
if (!job) {
|
|
563
|
-
if (services.length === 1) {
|
|
564
|
-
context.writer.writeError(
|
|
565
|
-
`Job "${nameOrId}" not found on server ${name}.`
|
|
566
|
-
);
|
|
567
|
-
}
|
|
568
|
-
continue;
|
|
569
|
-
}
|
|
570
760
|
if (services.length > 1) {
|
|
571
|
-
context
|
|
572
|
-
context.writer.wrapInColor(
|
|
573
|
-
`Server: ${name}`,
|
|
574
|
-
cliCore.CliForegroundColor.Cyan
|
|
575
|
-
)
|
|
576
|
-
);
|
|
761
|
+
writeServerHeader(context, name);
|
|
577
762
|
}
|
|
578
763
|
const history = await service.getHistory(job.id, {
|
|
579
764
|
limit,
|
|
@@ -584,7 +769,7 @@ var CliJobsCommandProcessor = class {
|
|
|
584
769
|
context.writer.writeInfo(
|
|
585
770
|
`No execution history for "${job.name}".`
|
|
586
771
|
);
|
|
587
|
-
|
|
772
|
+
continue;
|
|
588
773
|
}
|
|
589
774
|
context.writer.writeln(
|
|
590
775
|
`Showing ${history.items.length} of ${history.total} executions for "${job.name}":`
|
|
@@ -606,7 +791,6 @@ var CliJobsCommandProcessor = class {
|
|
|
606
791
|
exec.error ? exec.error.substring(0, 40) : "-"
|
|
607
792
|
]);
|
|
608
793
|
context.writer.writeTable(headers, rows);
|
|
609
|
-
return;
|
|
610
794
|
} catch (e) {
|
|
611
795
|
context.writer.writeError(
|
|
612
796
|
`Error on server ${name}: ${e.message}`
|
|
@@ -616,9 +800,9 @@ var CliJobsCommandProcessor = class {
|
|
|
616
800
|
}
|
|
617
801
|
// ── Logs ─────────────────────────────────────────────────────────
|
|
618
802
|
async handleLogs(cmd, context) {
|
|
619
|
-
const nameOrId = (cmd.value ?? "")
|
|
803
|
+
const nameOrId = cliCore.joinShellWords(cmd.value ?? "");
|
|
620
804
|
if (!nameOrId) {
|
|
621
|
-
context.writer.writeError("Usage: jobs logs <id|name>");
|
|
805
|
+
context.writer.writeError("Usage: server jobs logs <id|name>");
|
|
622
806
|
return;
|
|
623
807
|
}
|
|
624
808
|
const services = getServices(context, cmd.args);
|
|
@@ -627,16 +811,11 @@ var CliJobsCommandProcessor = class {
|
|
|
627
811
|
return;
|
|
628
812
|
}
|
|
629
813
|
const execId = cmd.args["exec"];
|
|
630
|
-
|
|
814
|
+
const matches = await findJobOnServers(context, services, nameOrId);
|
|
815
|
+
for (const { name, service, job } of matches) {
|
|
631
816
|
try {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (services.length === 1) {
|
|
635
|
-
context.writer.writeError(
|
|
636
|
-
`Job "${nameOrId}" not found on server ${name}.`
|
|
637
|
-
);
|
|
638
|
-
}
|
|
639
|
-
continue;
|
|
817
|
+
if (services.length > 1) {
|
|
818
|
+
writeServerHeader(context, name);
|
|
640
819
|
}
|
|
641
820
|
let execution;
|
|
642
821
|
if (execId) {
|
|
@@ -649,27 +828,19 @@ var CliJobsCommandProcessor = class {
|
|
|
649
828
|
context.writer.writeInfo(
|
|
650
829
|
`No executions found for "${job.name}".`
|
|
651
830
|
);
|
|
652
|
-
|
|
831
|
+
continue;
|
|
653
832
|
}
|
|
654
833
|
execution = await service.getExecution(
|
|
655
834
|
job.id,
|
|
656
835
|
history.items[0].id
|
|
657
836
|
);
|
|
658
837
|
}
|
|
659
|
-
if (services.length > 1) {
|
|
660
|
-
context.writer.writeln(
|
|
661
|
-
context.writer.wrapInColor(
|
|
662
|
-
`Server: ${name}`,
|
|
663
|
-
cliCore.CliForegroundColor.Cyan
|
|
664
|
-
)
|
|
665
|
-
);
|
|
666
|
-
}
|
|
667
838
|
context.writer.writeln(
|
|
668
839
|
`Logs for "${job.name}" execution ${execution.id.substring(0, 8)} (${statusColor(execution.status, context.writer)}):`
|
|
669
840
|
);
|
|
670
841
|
if (!execution.logs || execution.logs.length === 0) {
|
|
671
842
|
context.writer.writeInfo(" No log entries.");
|
|
672
|
-
|
|
843
|
+
continue;
|
|
673
844
|
}
|
|
674
845
|
for (const entry of execution.logs) {
|
|
675
846
|
const ts = new Date(entry.timestamp).toLocaleTimeString();
|
|
@@ -681,7 +852,6 @@ var CliJobsCommandProcessor = class {
|
|
|
681
852
|
` ${context.writer.wrapInColor(ts, cliCore.CliForegroundColor.White)} ${level} ${entry.message}`
|
|
682
853
|
);
|
|
683
854
|
}
|
|
684
|
-
return;
|
|
685
855
|
} catch (e) {
|
|
686
856
|
context.writer.writeError(
|
|
687
857
|
`Error on server ${name}: ${e.message}`
|
|
@@ -690,10 +860,15 @@ var CliJobsCommandProcessor = class {
|
|
|
690
860
|
}
|
|
691
861
|
}
|
|
692
862
|
// ── Edit ─────────────────────────────────────────────────────────
|
|
863
|
+
/**
|
|
864
|
+
* Prompt for each setting; Enter keeps the current value. Ctrl+C or
|
|
865
|
+
* Escape at any prompt (the reader resolves null) cancels the whole edit
|
|
866
|
+
* and nothing is sent. A job on several servers needs --server.
|
|
867
|
+
*/
|
|
693
868
|
async handleEdit(cmd, context) {
|
|
694
|
-
const nameOrId = (cmd.value ?? "")
|
|
869
|
+
const nameOrId = cliCore.joinShellWords(cmd.value ?? "");
|
|
695
870
|
if (!nameOrId) {
|
|
696
|
-
context.writer.writeError("Usage: jobs edit <id|name>");
|
|
871
|
+
context.writer.writeError("Usage: server jobs edit <id|name>");
|
|
697
872
|
return;
|
|
698
873
|
}
|
|
699
874
|
const services = getServices(context, cmd.args);
|
|
@@ -701,111 +876,94 @@ var CliJobsCommandProcessor = class {
|
|
|
701
876
|
context.writer.writeInfo("No connected servers.");
|
|
702
877
|
return;
|
|
703
878
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
context.writer.writeInfo("Edit cancelled.");
|
|
749
|
-
return;
|
|
750
|
-
}
|
|
751
|
-
if (newSchedule.trim()) {
|
|
752
|
-
update.schedule = newSchedule.trim();
|
|
753
|
-
}
|
|
754
|
-
if (!newSchedule.trim()) {
|
|
755
|
-
const newInterval = await context.reader.readLine(
|
|
756
|
-
`Interval (e.g. 30s, 5m) [${job.interval ? `${job.interval}ms` : "none"}]: `
|
|
757
|
-
);
|
|
758
|
-
if (newInterval != null && newInterval.trim()) {
|
|
759
|
-
update.interval = newInterval.trim();
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
const newRetries = await context.reader.readLine(
|
|
763
|
-
`Max retries [${job.maxRetries}]: `
|
|
764
|
-
);
|
|
765
|
-
if (newRetries != null && newRetries.trim()) {
|
|
766
|
-
const parsed = parseInt(newRetries.trim(), 10);
|
|
767
|
-
if (!isNaN(parsed)) {
|
|
768
|
-
update.maxRetries = parsed;
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
const newTimeout = await context.reader.readLine(
|
|
772
|
-
`Timeout (e.g. 5m, 1h) [${job.timeout ? `${job.timeout}ms` : "none"}]: `
|
|
773
|
-
);
|
|
774
|
-
if (newTimeout != null && newTimeout.trim()) {
|
|
775
|
-
update.timeout = newTimeout.trim();
|
|
776
|
-
}
|
|
777
|
-
const newOverlap = await context.reader.readLine(
|
|
778
|
-
`Overlap policy (skip/queue/cancel) [${job.overlapPolicy}]: `
|
|
779
|
-
);
|
|
780
|
-
if (newOverlap != null && newOverlap.trim() && ["skip", "queue", "cancel"].includes(
|
|
781
|
-
newOverlap.trim().toLowerCase()
|
|
782
|
-
)) {
|
|
783
|
-
update.overlapPolicy = newOverlap.trim().toLowerCase();
|
|
784
|
-
}
|
|
785
|
-
if (Object.keys(update).length === 0) {
|
|
786
|
-
context.writer.writeInfo("No changes made.");
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
const confirm = await context.reader.readConfirm(
|
|
790
|
-
"Apply changes?"
|
|
879
|
+
const matches = await findJobOnServers(context, services, nameOrId);
|
|
880
|
+
if (matches.length === 0) {
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
if (matches.length > 1) {
|
|
884
|
+
context.writer.writeError(
|
|
885
|
+
`Job "${nameOrId}" is on ${matches.length} servers (${matches.map((m) => m.name).join(", ")}). Use --server <name> to choose the one to edit.`
|
|
886
|
+
);
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
const { name, service, job } = matches[0];
|
|
890
|
+
const cancelled = () => {
|
|
891
|
+
context.writer.writeInfo("Edit cancelled.");
|
|
892
|
+
};
|
|
893
|
+
const aborted = () => !!context.signal?.aborted;
|
|
894
|
+
const ask = async (prompt) => {
|
|
895
|
+
if (aborted()) return null;
|
|
896
|
+
const answer = await context.reader.readLine(prompt);
|
|
897
|
+
return answer == null || aborted() ? null : answer.trim();
|
|
898
|
+
};
|
|
899
|
+
try {
|
|
900
|
+
context.writer.writeln(
|
|
901
|
+
`Editing job "${context.writer.wrapInColor(job.name, cliCore.CliForegroundColor.Cyan)}" on server ${name}`
|
|
902
|
+
);
|
|
903
|
+
context.writer.writeln(
|
|
904
|
+
"Press Enter to keep current value, or type a new value. Ctrl+C cancels."
|
|
905
|
+
);
|
|
906
|
+
context.writer.writeln("");
|
|
907
|
+
const update = {};
|
|
908
|
+
const newDesc = await ask(`Description [${job.description}]: `);
|
|
909
|
+
if (newDesc == null) return cancelled();
|
|
910
|
+
if (newDesc) update.description = newDesc;
|
|
911
|
+
const newGroup = await ask(`Group [${job.group ?? "none"}]: `);
|
|
912
|
+
if (newGroup == null) return cancelled();
|
|
913
|
+
if (newGroup) update.group = newGroup;
|
|
914
|
+
const currentSchedule = job.schedule ?? (job.interval ? `interval: ${job.interval}ms` : "none");
|
|
915
|
+
const newSchedule = await ask(
|
|
916
|
+
`Cron schedule [${currentSchedule}]: `
|
|
917
|
+
);
|
|
918
|
+
if (newSchedule == null) return cancelled();
|
|
919
|
+
if (newSchedule) update.schedule = newSchedule;
|
|
920
|
+
if (!newSchedule) {
|
|
921
|
+
const newInterval = await ask(
|
|
922
|
+
`Interval (e.g. 30s, 5m) [${job.interval ? `${job.interval}ms` : "none"}]: `
|
|
791
923
|
);
|
|
792
|
-
if (
|
|
793
|
-
|
|
794
|
-
|
|
924
|
+
if (newInterval == null) return cancelled();
|
|
925
|
+
if (newInterval) update.interval = newInterval;
|
|
926
|
+
}
|
|
927
|
+
const newRetries = await ask(`Max retries [${job.maxRetries}]: `);
|
|
928
|
+
if (newRetries == null) return cancelled();
|
|
929
|
+
if (newRetries) {
|
|
930
|
+
const parsed = parseInt(newRetries, 10);
|
|
931
|
+
if (!isNaN(parsed)) {
|
|
932
|
+
update.maxRetries = parsed;
|
|
795
933
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
934
|
+
}
|
|
935
|
+
const newTimeout = await ask(
|
|
936
|
+
`Timeout (e.g. 5m, 1h) [${job.timeout ? `${job.timeout}ms` : "none"}]: `
|
|
937
|
+
);
|
|
938
|
+
if (newTimeout == null) return cancelled();
|
|
939
|
+
if (newTimeout) update.timeout = newTimeout;
|
|
940
|
+
const newOverlap = await ask(
|
|
941
|
+
`Overlap policy (skip/queue/cancel) [${job.overlapPolicy}]: `
|
|
942
|
+
);
|
|
943
|
+
if (newOverlap == null) return cancelled();
|
|
944
|
+
if (newOverlap && ["skip", "queue", "cancel"].includes(newOverlap.toLowerCase())) {
|
|
945
|
+
update.overlapPolicy = newOverlap.toLowerCase();
|
|
946
|
+
}
|
|
947
|
+
if (Object.keys(update).length === 0) {
|
|
948
|
+
context.writer.writeInfo("No changes made.");
|
|
800
949
|
return;
|
|
801
|
-
} catch (e) {
|
|
802
|
-
context.writer.writeError(
|
|
803
|
-
`Error on server ${name}: ${e.message}`
|
|
804
|
-
);
|
|
805
950
|
}
|
|
951
|
+
const confirm = aborted() ? null : await context.reader.readConfirm("Apply changes?");
|
|
952
|
+
if (!confirm || aborted()) return cancelled();
|
|
953
|
+
await service.updateJob(job.id, update);
|
|
954
|
+
context.writer.writeSuccess(
|
|
955
|
+
`Job "${job.name}" updated successfully.`
|
|
956
|
+
);
|
|
957
|
+
} catch (e) {
|
|
958
|
+
context.writer.writeError(`Error on server ${name}: ${e.message}`);
|
|
806
959
|
}
|
|
807
960
|
}
|
|
808
961
|
// ── Watch ────────────────────────────────────────────────────────
|
|
962
|
+
/**
|
|
963
|
+
* Stream job events until Ctrl+C (context.onAbort / context.signal) or
|
|
964
|
+
* until every watched server has closed its connection. On exit the
|
|
965
|
+
* sockets are closed and every subscription and listener is removed.
|
|
966
|
+
*/
|
|
809
967
|
async handleWatch(cmd, context) {
|
|
810
968
|
const manager = context.services.getRequired("cli-server-manager");
|
|
811
969
|
if (!manager || !manager.connections) {
|
|
@@ -813,6 +971,18 @@ var CliJobsCommandProcessor = class {
|
|
|
813
971
|
return;
|
|
814
972
|
}
|
|
815
973
|
const targetServer = cmd.args["server"];
|
|
974
|
+
const targets = [];
|
|
975
|
+
for (const [serverName, connection] of manager.connections) {
|
|
976
|
+
if (targetServer && serverName !== targetServer) continue;
|
|
977
|
+
if (!connection.connected) continue;
|
|
978
|
+
targets.push([serverName, connection]);
|
|
979
|
+
}
|
|
980
|
+
if (targets.length === 0) {
|
|
981
|
+
context.writer.writeInfo(
|
|
982
|
+
targetServer ? `Server "${targetServer}" is not connected.` : "No connected servers."
|
|
983
|
+
);
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
816
986
|
context.writer.writeln(
|
|
817
987
|
context.writer.wrapInColor(
|
|
818
988
|
"Watching job events... (press Ctrl+C to stop)",
|
|
@@ -820,38 +990,60 @@ var CliJobsCommandProcessor = class {
|
|
|
820
990
|
)
|
|
821
991
|
);
|
|
822
992
|
context.writer.writeln("");
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
993
|
+
const open = /* @__PURE__ */ new Set();
|
|
994
|
+
let stopped = false;
|
|
995
|
+
let reason = "aborted";
|
|
996
|
+
let resolveDone;
|
|
997
|
+
const done = new Promise((resolve) => resolveDone = resolve);
|
|
998
|
+
const closeSocket = (ws) => {
|
|
999
|
+
ws.onmessage = null;
|
|
1000
|
+
ws.onerror = null;
|
|
1001
|
+
ws.onclose = null;
|
|
1002
|
+
try {
|
|
1003
|
+
ws.close();
|
|
1004
|
+
} catch {
|
|
830
1005
|
}
|
|
831
1006
|
};
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
1007
|
+
const onAbortSignal = () => stop("aborted");
|
|
1008
|
+
const abortSub = context.onAbort?.subscribe(onAbortSignal);
|
|
1009
|
+
context.signal?.addEventListener("abort", onAbortSignal);
|
|
1010
|
+
function stop(why) {
|
|
1011
|
+
if (stopped) return;
|
|
1012
|
+
stopped = true;
|
|
1013
|
+
reason = why;
|
|
1014
|
+
abortSub?.unsubscribe();
|
|
1015
|
+
context.signal?.removeEventListener("abort", onAbortSignal);
|
|
1016
|
+
for (const ws of open) closeSocket(ws);
|
|
1017
|
+
open.clear();
|
|
1018
|
+
resolveDone();
|
|
1019
|
+
}
|
|
1020
|
+
if (context.signal?.aborted) {
|
|
1021
|
+
stop("aborted");
|
|
1022
|
+
}
|
|
1023
|
+
const multiServer = targets.length > 1;
|
|
1024
|
+
for (const [serverName, connection] of targets) {
|
|
1025
|
+
if (stopped) break;
|
|
836
1026
|
const config = connection.config;
|
|
837
1027
|
const baseUrl = config.url.endsWith("/") ? config.url.slice(0, -1) : config.url;
|
|
838
|
-
const wsUrl = await cliCore.resolveServerWebSocketUrl(
|
|
839
|
-
context.services,
|
|
840
|
-
serverName,
|
|
841
|
-
baseUrl.replace(/^https:/, "wss:").replace(/^http:/, "ws:") + "/ws/v1/qcli/events",
|
|
842
|
-
config.headers
|
|
843
|
-
);
|
|
844
1028
|
try {
|
|
1029
|
+
const wsUrl = await cliCore.resolveServerWebSocketUrl(
|
|
1030
|
+
context.services,
|
|
1031
|
+
serverName,
|
|
1032
|
+
baseUrl.replace(/^https:/, "wss:").replace(/^http:/, "ws:") + "/ws/v1/qcli/events",
|
|
1033
|
+
config.headers
|
|
1034
|
+
);
|
|
1035
|
+
if (stopped) break;
|
|
845
1036
|
const ws = new WebSocket(wsUrl);
|
|
846
|
-
|
|
1037
|
+
open.add(ws);
|
|
847
1038
|
ws.onmessage = (event) => {
|
|
1039
|
+
if (stopped) return;
|
|
848
1040
|
try {
|
|
849
1041
|
const data = JSON.parse(event.data);
|
|
850
1042
|
if (!data.type || !data.type.startsWith("job:")) {
|
|
851
1043
|
return;
|
|
852
1044
|
}
|
|
853
1045
|
const ts = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
854
|
-
const serverPrefix =
|
|
1046
|
+
const serverPrefix = multiServer ? context.writer.wrapInColor(
|
|
855
1047
|
`[${serverName}] `,
|
|
856
1048
|
cliCore.CliForegroundColor.Cyan
|
|
857
1049
|
) : "";
|
|
@@ -879,11 +1071,19 @@ var CliJobsCommandProcessor = class {
|
|
|
879
1071
|
}
|
|
880
1072
|
};
|
|
881
1073
|
ws.onerror = () => {
|
|
1074
|
+
if (stopped) return;
|
|
882
1075
|
context.writer.writeError(
|
|
883
1076
|
`WebSocket error on server ${serverName}`
|
|
884
1077
|
);
|
|
885
1078
|
};
|
|
886
1079
|
ws.onclose = () => {
|
|
1080
|
+
if (stopped || !open.delete(ws)) return;
|
|
1081
|
+
context.writer.writeWarning(
|
|
1082
|
+
`Connection to server ${serverName} closed.`
|
|
1083
|
+
);
|
|
1084
|
+
if (open.size === 0) {
|
|
1085
|
+
stop("closed");
|
|
1086
|
+
}
|
|
887
1087
|
};
|
|
888
1088
|
} catch (e) {
|
|
889
1089
|
context.writer.writeError(
|
|
@@ -891,22 +1091,23 @@ var CliJobsCommandProcessor = class {
|
|
|
891
1091
|
);
|
|
892
1092
|
}
|
|
893
1093
|
}
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
});
|
|
899
|
-
if (context.signal) {
|
|
900
|
-
context.signal.addEventListener("abort", () => {
|
|
901
|
-
sub.unsubscribe();
|
|
902
|
-
resolve();
|
|
903
|
-
});
|
|
904
|
-
}
|
|
905
|
-
});
|
|
1094
|
+
if (!stopped && open.size === 0) {
|
|
1095
|
+
stop("closed");
|
|
1096
|
+
}
|
|
1097
|
+
await done;
|
|
906
1098
|
context.writer.writeln("");
|
|
907
|
-
context.writer.writeInfo(
|
|
1099
|
+
context.writer.writeInfo(
|
|
1100
|
+
reason === "closed" ? "Stopped watching job events: no server connection left." : "Stopped watching job events."
|
|
1101
|
+
);
|
|
908
1102
|
}
|
|
909
1103
|
};
|
|
1104
|
+
var PAST_TENSE = {
|
|
1105
|
+
trigger: "triggered",
|
|
1106
|
+
pause: "paused",
|
|
1107
|
+
resume: "resumed",
|
|
1108
|
+
stop: "stopped",
|
|
1109
|
+
cancel: "cancelled"
|
|
1110
|
+
};
|
|
910
1111
|
var JOB_NAME_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
911
1112
|
"info",
|
|
912
1113
|
"trigger",
|
|
@@ -975,7 +1176,7 @@ var CliJobNameCompletionProvider = class {
|
|
|
975
1176
|
};
|
|
976
1177
|
|
|
977
1178
|
// src/lib/version.ts
|
|
978
|
-
var LIBRARY_VERSION = "2.0.0-beta.
|
|
1179
|
+
var LIBRARY_VERSION = "2.0.0-beta.18";
|
|
979
1180
|
var API_VERSION = 2;
|
|
980
1181
|
var completionProvider = new CliJobNameCompletionProvider();
|
|
981
1182
|
var jobsModule = {
|