@stacksjs/actions 0.70.87 → 0.70.90
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/dist/action.js +78 -2
- package/dist/actions.js +2 -2
- package/dist/add.js +20 -2
- package/dist/ai/request-model-access.js +10 -2
- package/dist/auth/client.js +44 -3
- package/dist/auth/prune.js +35 -2
- package/dist/auth/setup.js +152 -36
- package/dist/auth/token.js +10 -2
- package/dist/blog-admin.d.ts +55 -0
- package/dist/blog-admin.js +156 -0
- package/dist/blog.d.ts +11 -0
- package/dist/blog.js +306 -56
- package/dist/build/cli.js +6 -2
- package/dist/build/component-libs.js +7 -2
- package/dist/build/core.js +55 -2
- package/dist/build/desktop.js +5 -2
- package/dist/build/docs.js +5 -2
- package/dist/build/frontend-static.js +123 -8
- package/dist/build/server.js +6 -2
- package/dist/build/stacks.js +8 -2
- package/dist/build/views.js +11 -2
- package/dist/build.js +64 -2
- package/dist/bump.js +162 -7
- package/dist/cdn/invalidate-cache.js +0 -1
- package/dist/changelog.js +27 -3
- package/dist/check/ports.js +16 -2
- package/dist/clean.js +4 -2
- package/dist/commit.js +12 -2
- package/dist/copy-types.js +10 -3
- package/dist/database/seed.js +26 -2
- package/dist/deploy/create-receipt-rule.js +36 -2
- package/dist/deploy/index.js +1318 -44
- package/dist/dev/api.js +94 -6
- package/dist/dev/components.js +7 -2
- package/dist/dev/dashboard-globals.js +89 -3
- package/dist/dev/dashboard-utils.js +380 -2
- package/dist/dev/dashboard.js +435 -8
- package/dist/dev/desktop.js +5 -2
- package/dist/dev/docs.js +24 -2
- package/dist/dev/index.js +29 -2
- package/dist/dev/migrate-watcher.js +74 -2
- package/dist/dev/system-tray.js +5 -2
- package/dist/dev/views.js +147 -2
- package/dist/discover-packages.js +32 -2
- package/dist/domains/add.js +61 -2
- package/dist/domains/purchase.js +66 -2
- package/dist/domains/remove.js +24 -2
- package/dist/examples.js +34 -2
- package/dist/find-projects.js +16 -2
- package/dist/fresh.js +17 -2
- package/dist/generate/action-types.js +9 -4
- package/dist/generate/component-meta.js +9 -3
- package/dist/generate/custom-cli-file.js +20 -3
- package/dist/generate/env-files.js +46 -6
- package/dist/generate/ide-helpers.js +8 -3
- package/dist/generate/index.js +158 -2
- package/dist/generate/lib-entries.js +16 -3
- package/dist/generate/pantry-file.js +46 -2
- package/dist/generate/symlink-core.js +2 -2
- package/dist/generate/types.js +3 -2
- package/dist/generate/vscode-custom-data.js +9 -3
- package/dist/generate/web-types.js +0 -1
- package/dist/helpers/component-meta.js +295 -2
- package/dist/helpers/index.js +1 -2
- package/dist/helpers/lib-entries.js +73 -2
- package/dist/helpers/package-json.js +45 -14
- package/dist/helpers/utils.js +105 -2
- package/dist/helpers/vscode-custom-data.js +30 -2
- package/dist/index.d.ts +13 -0
- package/dist/index.js +50 -2
- package/dist/key-generate.js +24 -2
- package/dist/lint/fix.js +4 -3
- package/dist/lint/index.js +4 -3
- package/dist/lint/lint.js +34 -2
- package/dist/make-command.js +64 -14
- package/dist/make-job.js +41 -16
- package/dist/make-policy.js +74 -26
- package/dist/make-resource.js +50 -21
- package/dist/make.js +328 -2
- package/dist/migrate/database.js +16 -2
- package/dist/migrate/fresh.js +31 -2
- package/dist/orm/base.js +0 -2
- package/dist/orm/test.js +0 -1
- package/dist/prepublish.js +16 -2
- package/dist/queue/clear.js +42 -2
- package/dist/queue/dlq-purge.js +28 -2
- package/dist/queue/dlq-retry.js +35 -2
- package/dist/queue/dlq.js +55 -5
- package/dist/queue/failed.js +69 -5
- package/dist/queue/flush.js +49 -3
- package/dist/queue/inspect.js +154 -8
- package/dist/queue/list.js +69 -5
- package/dist/queue/monitor.js +94 -6
- package/dist/queue/pause.js +28 -2
- package/dist/queue/quarantine.js +42 -3
- package/dist/queue/resume.js +27 -2
- package/dist/queue/retry.js +41 -2
- package/dist/queue/schedule-list.js +33 -5
- package/dist/queue/schedule.js +12 -2
- package/dist/queue/status.js +68 -5
- package/dist/queue/table.js +10 -2
- package/dist/queue/unquarantine.js +27 -2
- package/dist/queue/work.js +57 -2
- package/dist/release.js +21 -3
- package/dist/route/list.js +78 -3
- package/dist/run-action.js +1 -2
- package/dist/saas/setup.js +9 -2
- package/dist/scaffold-crud.js +164 -40
- package/dist/schedule/run.js +7 -2
- package/dist/search/flush.js +10 -2
- package/dist/search/import.js +10 -2
- package/dist/search/settings-list.js +10 -2
- package/dist/search/settings.js +9 -2
- package/dist/serve/api.js +35 -2
- package/dist/setup/index.js +1 -2
- package/dist/setup/ssl.js +271 -2
- package/dist/stacks.js +265 -2
- package/dist/templates.js +301 -2
- package/dist/test/feature.js +11 -2
- package/dist/test/index.js +11 -2
- package/dist/test/ui.js +4 -2
- package/dist/test/unit.js +11 -2
- package/dist/typecheck.js +4 -2
- package/dist/types.js +16 -2
- package/dist/upgrade/binary.js +29 -2
- package/dist/upgrade/bun.js +0 -1
- package/dist/upgrade/dependencies.js +0 -2
- package/dist/upgrade/framework-utils.js +193 -2
- package/dist/upgrade/framework.js +310 -7
- package/dist/upgrade/index.js +17 -2
- package/dist/upgrade/packages.js +99 -12
- package/dist/upgrade/shell.js +40 -4
- package/dist/upgrade.js +38 -2
- package/package.json +16 -16
- package/dist/chunk-0c8sd1t6.js +0 -2
- package/dist/chunk-0g2nzhx9.js +0 -240
- package/dist/chunk-0gadhvn7.js +0 -3
- package/dist/chunk-0h27aa4r.js +0 -93
- package/dist/chunk-3peh8kqs.js +0 -851
- package/dist/chunk-62gdfav8.js +0 -3
- package/dist/chunk-6bk53y02.js +0 -3
- package/dist/chunk-78c5n3s2.js +0 -3
- package/dist/chunk-c74qv38e.js +0 -17
- package/dist/chunk-cdk2r2jd.js +0 -1
- package/dist/chunk-dbz9dp2h.js +0 -3
- package/dist/chunk-e142dheq.js +0 -3
- package/dist/chunk-ec4gky40.js +0 -3
- package/dist/chunk-h3d81wrg.js +0 -3
- package/dist/chunk-m3q0x4h0.js +0 -688
- package/dist/chunk-mqgbyhph.js +0 -5
- package/dist/chunk-n24m8prb.js +0 -3
- package/dist/chunk-n5eqwhck.js +0 -7
- package/dist/chunk-nsvnqv8y.js +0 -5
- package/dist/chunk-nty6mmx4.js +0 -283
- package/dist/chunk-s735m9mg.js +0 -1
- package/dist/chunk-tpb8jgsk.js +0 -7
- package/dist/chunk-tsbk5vne.js +0 -3
- package/dist/chunk-xg9xscqz.js +0 -1
- package/dist/chunk-y6e448he.js +0 -7
package/dist/orm/base.js
CHANGED
package/dist/orm/test.js
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// @bun
|
package/dist/prepublish.js
CHANGED
|
@@ -1,2 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { NpmScript } from "@stacksjs/enums";
|
|
3
|
+
import { log } from "@stacksjs/logging";
|
|
4
|
+
import { runtimePath } from "@stacksjs/path";
|
|
5
|
+
import { ExitCode } from "@stacksjs/types";
|
|
6
|
+
import { runNpmScript } from "@stacksjs/utils";
|
|
7
|
+
log.info("Running prepublish command...");
|
|
8
|
+
const result = await runNpmScript(NpmScript.BuildStacks, {
|
|
9
|
+
verbose: !0,
|
|
10
|
+
cwd: runtimePath()
|
|
11
|
+
});
|
|
12
|
+
if (result.isErr) {
|
|
13
|
+
log.error(Error("There was an error while prepublishing your stack"), result.error);
|
|
14
|
+
process.exit(ExitCode.FatalError);
|
|
15
|
+
}
|
|
16
|
+
log.success("Prepublishing completed");
|
package/dist/queue/clear.js
CHANGED
|
@@ -1,2 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { log } from "@stacksjs/logging";
|
|
3
|
+
import { Job } from "@stacksjs/orm";
|
|
4
|
+
const options = parseArgs(), queueName = options.queue, force = options.force === "true";
|
|
5
|
+
try {
|
|
6
|
+
if (!force) {
|
|
7
|
+
log.warn("This will delete all jobs from the queue. Use --force to confirm.");
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
let deletedCount = 0;
|
|
11
|
+
if (queueName) {
|
|
12
|
+
log.info(`Clearing all jobs from queue "${queueName}"...`);
|
|
13
|
+
const jobs = await Job.where("queue", queueName).get();
|
|
14
|
+
deletedCount = jobs.length;
|
|
15
|
+
for (const job of jobs)
|
|
16
|
+
await job.delete();
|
|
17
|
+
} else {
|
|
18
|
+
log.info("Clearing all jobs from all queues...");
|
|
19
|
+
const jobs = await Job.all();
|
|
20
|
+
deletedCount = jobs.length;
|
|
21
|
+
for (const job of jobs)
|
|
22
|
+
await job.delete();
|
|
23
|
+
}
|
|
24
|
+
log.success(`Cleared ${deletedCount} job(s)`);
|
|
25
|
+
process.exit(0);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
log.error("Failed to clear jobs", error);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
function parseArgs() {
|
|
31
|
+
const args = {};
|
|
32
|
+
process.argv.forEach((arg) => {
|
|
33
|
+
if (arg.startsWith("--")) {
|
|
34
|
+
const [key, value] = arg.slice(2).split("=");
|
|
35
|
+
if (key && value)
|
|
36
|
+
args[key] = value;
|
|
37
|
+
else if (key)
|
|
38
|
+
args[key] = "true";
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
return args;
|
|
42
|
+
}
|
package/dist/queue/dlq-purge.js
CHANGED
|
@@ -1,2 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { log } from "@stacksjs/logging";
|
|
3
|
+
import { purgeDeadLetterJobs } from "@stacksjs/queue";
|
|
4
|
+
const options = parseArgs(), days = options.olderThanDays ? Number.parseInt(options.olderThanDays, 10) : options["older-than-days"] ? Number.parseInt(options["older-than-days"], 10) : 30;
|
|
5
|
+
if (!Number.isFinite(days) || days < 1) {
|
|
6
|
+
log.error(`Invalid --older-than-days value '${options.olderThanDays ?? options["older-than-days"]}'`);
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
log.info(`Pruning dead-letter rows older than ${days} day(s)...`);
|
|
11
|
+
const deleted = await purgeDeadLetterJobs(days);
|
|
12
|
+
log.success(`Deleted ${deleted} dead-letter row(s)`);
|
|
13
|
+
process.exit(0);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
log.error("Failed to purge dead-letter jobs", error);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
function parseArgs() {
|
|
19
|
+
const args = {};
|
|
20
|
+
process.argv.forEach((arg) => {
|
|
21
|
+
if (arg.startsWith("--")) {
|
|
22
|
+
const [key, value] = arg.slice(2).split("=");
|
|
23
|
+
if (key && value)
|
|
24
|
+
args[key] = value;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return args;
|
|
28
|
+
}
|
package/dist/queue/dlq-retry.js
CHANGED
|
@@ -1,2 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { log } from "@stacksjs/logging";
|
|
3
|
+
import { retryDeadLetterJob } from "@stacksjs/queue";
|
|
4
|
+
const options = parseArgs(), idArg = options.id;
|
|
5
|
+
if (!idArg) {
|
|
6
|
+
log.error("Usage: buddy queue:dlq:retry --id=<id>");
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
const id = Number.parseInt(idArg, 10);
|
|
10
|
+
if (Number.isNaN(id)) {
|
|
11
|
+
log.error("Invalid id provided");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
if (!await retryDeadLetterJob(id)) {
|
|
16
|
+
log.error(`Dead-letter job ${id} not found (or DLQ table missing)`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
log.success(`Re-enqueued dead-letter job ${id}`);
|
|
20
|
+
process.exit(0);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
log.error("Failed to re-enqueue dead-letter job", error);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
function parseArgs() {
|
|
26
|
+
const args = {};
|
|
27
|
+
process.argv.forEach((arg) => {
|
|
28
|
+
if (arg.startsWith("--")) {
|
|
29
|
+
const [key, value] = arg.slice(2).split("=");
|
|
30
|
+
if (key && value)
|
|
31
|
+
args[key] = value;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return args;
|
|
35
|
+
}
|
package/dist/queue/dlq.js
CHANGED
|
@@ -1,5 +1,55 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { log } from "@stacksjs/logging";
|
|
3
|
+
import { listDeadLetterJobs } from "@stacksjs/queue";
|
|
4
|
+
const options = parseArgs(), queueName = options.queue || void 0, reason = options.reason || void 0, sinceArg = options.since, limit = options.limit ? Number.parseInt(options.limit, 10) : 100;
|
|
5
|
+
try {
|
|
6
|
+
log.info(`Fetching dead-letter jobs...
|
|
7
|
+
`);
|
|
8
|
+
const sinceCutoffMs = sinceArg ? parseSinceDuration(sinceArg) ?? void 0 : void 0, rows = await listDeadLetterJobs({ queue: queueName, reason, sinceCutoffMs, limit });
|
|
9
|
+
if (rows.length === 0) {
|
|
10
|
+
console.log("\u2713 No dead-letter jobs found");
|
|
11
|
+
process.exit(0);
|
|
12
|
+
}
|
|
13
|
+
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
14
|
+
console.log("\u2502 ID \u2502 Queue \u2502 Reason \u2502 Failures \u2502 Dead-Lettered At \u2502");
|
|
15
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
16
|
+
for (const row of rows) {
|
|
17
|
+
const id = String(row.id).padEnd(3), q = (row.queue || "default").substring(0, 32).padEnd(32), r = (row.reason || "unknown").substring(0, 16).padEnd(16), f = String(row.total_failures ?? 1).padEnd(8), dt = (row.dead_lettered_at || "N/A").substring(0, 24).padEnd(24);
|
|
18
|
+
console.log(`\u2502 ${id} \u2502 ${q} \u2502 ${r} \u2502 ${f} \u2502 ${dt} \u2502`);
|
|
19
|
+
}
|
|
20
|
+
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
21
|
+
console.log(`
|
|
22
|
+
Showing ${rows.length} dead-letter job(s)`);
|
|
23
|
+
process.exit(0);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
26
|
+
if (/no such table:\s*dead_letter_jobs\b/i.test(message)) {
|
|
27
|
+
process.stdout.write(`Dead-letter queue table is not set up yet.
|
|
28
|
+
`);
|
|
29
|
+
process.stdout.write("Run `buddy queue:table` to create the migrations, then `buddy migrate` to apply them.\n");
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
log.error("Failed to fetch dead-letter jobs", error);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
function parseArgs() {
|
|
36
|
+
const args = {};
|
|
37
|
+
process.argv.forEach((arg) => {
|
|
38
|
+
if (arg.startsWith("--")) {
|
|
39
|
+
const [key, value] = arg.slice(2).split("=");
|
|
40
|
+
if (key && value)
|
|
41
|
+
args[key] = value;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
return args;
|
|
45
|
+
}
|
|
46
|
+
function parseSinceDuration(input) {
|
|
47
|
+
const m = /^(\d+)([smhd])$/.exec(input.trim());
|
|
48
|
+
if (!m)
|
|
49
|
+
return null;
|
|
50
|
+
const n = Number(m[1]);
|
|
51
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
52
|
+
return null;
|
|
53
|
+
const mult = m[2] === "s" ? 1000 : m[2] === "m" ? 60000 : m[2] === "h" ? 3600000 : 86400000;
|
|
54
|
+
return Date.now() - n * mult;
|
|
55
|
+
}
|
package/dist/queue/failed.js
CHANGED
|
@@ -1,5 +1,69 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { log } from "@stacksjs/logging";
|
|
3
|
+
import { FailedJob } from "@stacksjs/orm";
|
|
4
|
+
const options = parseArgs(), queueName = options.queue, sinceArg = options.since, sinceCutoff = sinceArg ? parseSinceDuration(sinceArg) : null;
|
|
5
|
+
try {
|
|
6
|
+
log.info(`Fetching failed jobs...
|
|
7
|
+
`);
|
|
8
|
+
let failedJobs;
|
|
9
|
+
if (queueName)
|
|
10
|
+
failedJobs = await FailedJob.where("queue", queueName).get();
|
|
11
|
+
else
|
|
12
|
+
failedJobs = await FailedJob.all();
|
|
13
|
+
if (sinceCutoff)
|
|
14
|
+
failedJobs = failedJobs.filter((j) => {
|
|
15
|
+
if (!j.failed_at)
|
|
16
|
+
return !1;
|
|
17
|
+
const ts = Date.parse(j.failed_at);
|
|
18
|
+
return Number.isFinite(ts) && ts >= sinceCutoff;
|
|
19
|
+
});
|
|
20
|
+
if (failedJobs.length === 0) {
|
|
21
|
+
if (sinceCutoff)
|
|
22
|
+
console.log(`\u2713 No failed jobs found since ${sinceArg}`);
|
|
23
|
+
else
|
|
24
|
+
console.log("\u2713 No failed jobs found");
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
28
|
+
console.log("\u2502 ID \u2502 Queue \u2502 Failed At \u2502 Exception \u2502");
|
|
29
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
30
|
+
for (const job of failedJobs) {
|
|
31
|
+
const id = String(job.id).padEnd(3), queue = (job.queue || "default").substring(0, 48).padEnd(48), failedAt = (job.failed_at || "N/A").substring(0, 21).padEnd(21), exception = (job.exception || "Unknown error").substring(0, 31).padEnd(31);
|
|
32
|
+
console.log(`\u2502 ${id} \u2502 ${queue} \u2502 ${failedAt} \u2502 ${exception} \u2502`);
|
|
33
|
+
}
|
|
34
|
+
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
35
|
+
console.log(`
|
|
36
|
+
Total: ${failedJobs.length} failed job(s)`);
|
|
37
|
+
process.exit(0);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
40
|
+
if (/no such table:\s*(?:jobs|failed_jobs)\b/i.test(message)) {
|
|
41
|
+
process.stdout.write(`Queue tables are not set up yet.
|
|
42
|
+
`);
|
|
43
|
+
process.stdout.write("Run `buddy queue:table` to create the migrations, then `buddy migrate` to apply them.\n");
|
|
44
|
+
process.exit(0);
|
|
45
|
+
}
|
|
46
|
+
log.error("Failed to fetch failed jobs", error);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
function parseArgs() {
|
|
50
|
+
const args = {};
|
|
51
|
+
process.argv.forEach((arg) => {
|
|
52
|
+
if (arg.startsWith("--")) {
|
|
53
|
+
const [key, value] = arg.slice(2).split("=");
|
|
54
|
+
if (key && value)
|
|
55
|
+
args[key] = value;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return args;
|
|
59
|
+
}
|
|
60
|
+
function parseSinceDuration(input) {
|
|
61
|
+
const m = /^(\d+)([smhd])$/.exec(input.trim());
|
|
62
|
+
if (!m)
|
|
63
|
+
return null;
|
|
64
|
+
const n = Number(m[1]);
|
|
65
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
66
|
+
return null;
|
|
67
|
+
const mult = m[2] === "s" ? 1000 : m[2] === "m" ? 60000 : m[2] === "h" ? 3600000 : 86400000;
|
|
68
|
+
return Date.now() - n * mult;
|
|
69
|
+
}
|
package/dist/queue/flush.js
CHANGED
|
@@ -1,3 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { log } from "@stacksjs/logging";
|
|
3
|
+
import { FailedJob } from "@stacksjs/orm";
|
|
4
|
+
const options = parseArgs(), queueName = options.queue, force = options.force === "true";
|
|
5
|
+
try {
|
|
6
|
+
if (!force) {
|
|
7
|
+
log.warn("This will permanently delete all failed jobs. Use --force to confirm.");
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
let deletedCount = 0;
|
|
11
|
+
if (queueName) {
|
|
12
|
+
log.info(`Flushing all failed jobs from queue "${queueName}"...`);
|
|
13
|
+
const failedJobs = await FailedJob.where("queue", queueName).get();
|
|
14
|
+
deletedCount = failedJobs.length;
|
|
15
|
+
for (const job of failedJobs)
|
|
16
|
+
await job.delete();
|
|
17
|
+
} else {
|
|
18
|
+
log.info("Flushing all failed jobs from all queues...");
|
|
19
|
+
const failedJobs = await FailedJob.all();
|
|
20
|
+
deletedCount = failedJobs.length;
|
|
21
|
+
for (const job of failedJobs)
|
|
22
|
+
await job.delete();
|
|
23
|
+
}
|
|
24
|
+
log.success(`Flushed ${deletedCount} failed job(s)`);
|
|
25
|
+
process.exit(0);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
28
|
+
if (/no such table:\s*(?:jobs|failed_jobs)\b/i.test(message)) {
|
|
29
|
+
process.stdout.write(`Queue tables are not set up yet.
|
|
30
|
+
`);
|
|
31
|
+
process.stdout.write("Run `buddy queue:table` to create the migrations, then `buddy migrate` to apply them.\n");
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
log.error("Failed to flush failed jobs", error);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
function parseArgs() {
|
|
38
|
+
const args = {};
|
|
39
|
+
process.argv.forEach((arg) => {
|
|
40
|
+
if (arg.startsWith("--")) {
|
|
41
|
+
const [key, value] = arg.slice(2).split("=");
|
|
42
|
+
if (key && value)
|
|
43
|
+
args[key] = value;
|
|
44
|
+
else if (key)
|
|
45
|
+
args[key] = "true";
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
return args;
|
|
49
|
+
}
|
package/dist/queue/inspect.js
CHANGED
|
@@ -1,8 +1,154 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { log } from "@stacksjs/logging";
|
|
3
|
+
import { Job, FailedJob } from "@stacksjs/orm";
|
|
4
|
+
const options = parseArgs(), jobId = options.id, failedFlag = options.failed === "true";
|
|
5
|
+
try {
|
|
6
|
+
if (!jobId) {
|
|
7
|
+
log.error("Please provide a job ID");
|
|
8
|
+
log.info("Usage: buddy queue:inspect --id=<jobId> [--failed]");
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
const id = Number.parseInt(jobId, 10);
|
|
12
|
+
if (Number.isNaN(id)) {
|
|
13
|
+
log.error("Invalid job ID provided");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
if (failedFlag) {
|
|
17
|
+
const failedResult = await FailedJob.find(id);
|
|
18
|
+
if (!failedResult) {
|
|
19
|
+
log.error(`Failed job with ID ${id} not found`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const job = failedResult;
|
|
23
|
+
console.log(`
|
|
24
|
+
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510`);
|
|
25
|
+
console.log("\u2502 Failed Job Details \u2502");
|
|
26
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
27
|
+
console.log(`\u2502 ID: ${String(job.id).padEnd(52)} \u2502`);
|
|
28
|
+
console.log(`\u2502 Queue: ${(job.queue || "default").padEnd(52)} \u2502`);
|
|
29
|
+
console.log(`\u2502 Connection: ${(job.connection || "database").padEnd(52)} \u2502`);
|
|
30
|
+
console.log(`\u2502 Failed At: ${(job.failed_at || "N/A").padEnd(52)} \u2502`);
|
|
31
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
32
|
+
console.log("\u2502 Exception: \u2502");
|
|
33
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
34
|
+
const exception = job.exception || "Unknown error", lines = exception.match(/.{1,62}/g) || [exception];
|
|
35
|
+
for (const line of lines.slice(0, 20))
|
|
36
|
+
console.log(`\u2502 ${line.padEnd(62)} \u2502`);
|
|
37
|
+
if (lines.length > 20)
|
|
38
|
+
console.log(`\u2502 ... (${lines.length - 20} more lines)`.padEnd(64) + " \u2502");
|
|
39
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
40
|
+
console.log("\u2502 Payload: \u2502");
|
|
41
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
42
|
+
if (job.payload)
|
|
43
|
+
try {
|
|
44
|
+
const payload = JSON.parse(job.payload);
|
|
45
|
+
console.log(`\u2502 Name: ${payload.name.padEnd(52)} \u2502`);
|
|
46
|
+
console.log(`\u2502 Path: ${payload.path.padEnd(52)} \u2502`);
|
|
47
|
+
console.log(`\u2502 Max Tries: ${String(payload.maxTries).padEnd(52)} \u2502`);
|
|
48
|
+
console.log("\u2502 Parameters: \u2502");
|
|
49
|
+
const paramLines = JSON.stringify(payload.params, null, 2).split(`
|
|
50
|
+
`);
|
|
51
|
+
for (const line of paramLines.slice(0, 15))
|
|
52
|
+
console.log(`\u2502 ${line.substring(0, 60).padEnd(60)} \u2502`);
|
|
53
|
+
if (paramLines.length > 15)
|
|
54
|
+
console.log(`\u2502 ... (${paramLines.length - 15} more lines)`.padEnd(64) + " \u2502");
|
|
55
|
+
} catch {
|
|
56
|
+
console.log(`\u2502 Raw: ${job.payload.substring(0, 58).padEnd(58)} \u2502`);
|
|
57
|
+
}
|
|
58
|
+
else
|
|
59
|
+
console.log("\u2502 (No payload) \u2502");
|
|
60
|
+
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
61
|
+
console.log(`
|
|
62
|
+
Actions:`);
|
|
63
|
+
console.log(` Retry this job: buddy queue:retry --id=${id}`);
|
|
64
|
+
console.log(` Delete this job: buddy queue:flush --id=${id}`);
|
|
65
|
+
} else {
|
|
66
|
+
const jobResult = await Job.find(id);
|
|
67
|
+
if (!jobResult) {
|
|
68
|
+
log.error(`Job with ID ${id} not found`);
|
|
69
|
+
log.info("Tip: Use --failed flag to inspect failed jobs");
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
const job = jobResult, now = Math.floor(Date.now() / 1000);
|
|
73
|
+
let status = "Pending";
|
|
74
|
+
if (job.reserved_at)
|
|
75
|
+
status = "Processing";
|
|
76
|
+
else if (job.available_at && job.available_at > now)
|
|
77
|
+
status = "Delayed";
|
|
78
|
+
console.log(`
|
|
79
|
+
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510`);
|
|
80
|
+
console.log("\u2502 Job Details \u2502");
|
|
81
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
82
|
+
console.log(`\u2502 ID: ${String(job.id).padEnd(50)} \u2502`);
|
|
83
|
+
console.log(`\u2502 Queue: ${(job.queue || "default").padEnd(50)} \u2502`);
|
|
84
|
+
console.log(`\u2502 Status: ${status.padEnd(50)} \u2502`);
|
|
85
|
+
console.log(`\u2502 Attempts: ${String(job.attempts || 0).padEnd(50)} \u2502`);
|
|
86
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
87
|
+
if (job.available_at) {
|
|
88
|
+
const availableDate = new Date(job.available_at * 1000);
|
|
89
|
+
console.log(`\u2502 Available At: ${availableDate.toISOString().padEnd(50)} \u2502`);
|
|
90
|
+
}
|
|
91
|
+
if (job.reserved_at) {
|
|
92
|
+
const reservedDate = new Date(job.reserved_at * 1000);
|
|
93
|
+
console.log(`\u2502 Reserved At: ${reservedDate.toISOString().padEnd(50)} \u2502`);
|
|
94
|
+
}
|
|
95
|
+
if (job.created_at)
|
|
96
|
+
console.log(`\u2502 Created At: ${String(job.created_at).padEnd(50)} \u2502`);
|
|
97
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
98
|
+
console.log("\u2502 Payload: \u2502");
|
|
99
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
100
|
+
if (job.payload)
|
|
101
|
+
try {
|
|
102
|
+
const payload = JSON.parse(job.payload);
|
|
103
|
+
console.log(`\u2502 Name: ${payload.name.padEnd(52)} \u2502`);
|
|
104
|
+
console.log(`\u2502 Path: ${payload.path.padEnd(52)} \u2502`);
|
|
105
|
+
console.log(`\u2502 Max Tries: ${String(payload.maxTries).padEnd(52)} \u2502`);
|
|
106
|
+
console.log(`\u2502 Timeout: ${String(payload.timeOut || "N/A").padEnd(52)} \u2502`);
|
|
107
|
+
console.log("\u2502 Parameters: \u2502");
|
|
108
|
+
const paramLines = JSON.stringify(payload.params, null, 2).split(`
|
|
109
|
+
`);
|
|
110
|
+
for (const line of paramLines.slice(0, 15))
|
|
111
|
+
console.log(`\u2502 ${line.substring(0, 60).padEnd(60)} \u2502`);
|
|
112
|
+
if (paramLines.length > 15)
|
|
113
|
+
console.log(`\u2502 ... (${paramLines.length - 15} more lines)`.padEnd(64) + " \u2502");
|
|
114
|
+
if (payload.classPayload)
|
|
115
|
+
try {
|
|
116
|
+
const classConfig = JSON.parse(payload.classPayload);
|
|
117
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
118
|
+
console.log("\u2502 Job Configuration: \u2502");
|
|
119
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
120
|
+
console.log(`\u2502 Tries: ${String(classConfig.tries || 3).padEnd(52)} \u2502`);
|
|
121
|
+
console.log(`\u2502 Timeout: ${String(classConfig.timeout || 60).padEnd(52)} \u2502`);
|
|
122
|
+
if (classConfig.backoff)
|
|
123
|
+
console.log(`\u2502 Backoff: ${String(JSON.stringify(classConfig.backoff)).substring(0, 52).padEnd(52)} \u2502`);
|
|
124
|
+
} catch {}
|
|
125
|
+
} catch {
|
|
126
|
+
console.log(`\u2502 Raw: ${job.payload.substring(0, 58).padEnd(58)} \u2502`);
|
|
127
|
+
}
|
|
128
|
+
else
|
|
129
|
+
console.log("\u2502 (No payload) \u2502");
|
|
130
|
+
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
131
|
+
if (status === "Delayed" && job.available_at) {
|
|
132
|
+
const waitTime = job.available_at - now;
|
|
133
|
+
console.log(`
|
|
134
|
+
This job will be available in ${waitTime} second(s)`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
process.exit(0);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
log.error("Failed to inspect job", error);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
function parseArgs() {
|
|
143
|
+
const args = {};
|
|
144
|
+
process.argv.forEach((arg) => {
|
|
145
|
+
if (arg.startsWith("--")) {
|
|
146
|
+
const [key, value] = arg.slice(2).split("=");
|
|
147
|
+
if (key && value)
|
|
148
|
+
args[key] = value;
|
|
149
|
+
else if (key)
|
|
150
|
+
args[key] = "true";
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
return args;
|
|
154
|
+
}
|
package/dist/queue/list.js
CHANGED
|
@@ -1,5 +1,69 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { log } from "@stacksjs/logging";
|
|
3
|
+
import { Job } from "@stacksjs/orm";
|
|
4
|
+
const options = parseArgs(), queueName = options.queue, statusFilter = options.status, limit = options.limit ? Number.parseInt(options.limit, 10) : 50;
|
|
5
|
+
try {
|
|
6
|
+
log.info(`Fetching queued jobs...
|
|
7
|
+
`);
|
|
8
|
+
let jobs = queueName ? await Job.where("queue", queueName).get() : await Job.all();
|
|
9
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
10
|
+
if (statusFilter === "pending")
|
|
11
|
+
jobs = jobs.filter((j) => !j.reserved_at && (j.available_at ?? 0) <= nowSec);
|
|
12
|
+
else if (statusFilter === "reserved")
|
|
13
|
+
jobs = jobs.filter((j) => Boolean(j.reserved_at));
|
|
14
|
+
else if (statusFilter === "delayed")
|
|
15
|
+
jobs = jobs.filter((j) => !j.reserved_at && (j.available_at ?? 0) > nowSec);
|
|
16
|
+
if (Number.isFinite(limit) && limit > 0)
|
|
17
|
+
jobs = jobs.slice(0, limit);
|
|
18
|
+
if (jobs.length === 0) {
|
|
19
|
+
console.log("\u2713 No queued jobs found");
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
23
|
+
console.log("\u2502 ID \u2502 Queue \u2502 Job \u2502 Attempts \u2502 Status \u2502 Available At \u2502");
|
|
24
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
25
|
+
for (const j of jobs) {
|
|
26
|
+
const jobAny = j, id = String(jobAny.id ?? "").padEnd(3), queue = String(jobAny.queue ?? "default").substring(0, 18).padEnd(18), jobName = extractJobName(jobAny.payload).substring(0, 32).padEnd(32), attempts = String(jobAny.attempts ?? 0).padEnd(8), status = (jobAny.reserved_at ? "reserved" : (jobAny.available_at ?? 0) > nowSec ? "delayed" : "pending").padEnd(8), avail = formatUnixTime(jobAny.available_at).padEnd(19);
|
|
27
|
+
console.log(`\u2502 ${id} \u2502 ${queue} \u2502 ${jobName} \u2502 ${attempts} \u2502 ${status} \u2502 ${avail} \u2502`);
|
|
28
|
+
}
|
|
29
|
+
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
30
|
+
console.log(`
|
|
31
|
+
Showing ${jobs.length} job(s)${queueName ? ` on queue '${queueName}'` : ""}${statusFilter ? ` (status=${statusFilter})` : ""}`);
|
|
32
|
+
process.exit(0);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
35
|
+
if (/no such table:\s*jobs\b/i.test(message)) {
|
|
36
|
+
process.stdout.write(`Queue tables are not set up yet.
|
|
37
|
+
`);
|
|
38
|
+
process.stdout.write("Run `buddy queue:table` to create the migrations, then `buddy migrate` to apply them.\n");
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
log.error("Failed to list queued jobs", error);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
function extractJobName(payload) {
|
|
45
|
+
if (typeof payload !== "string")
|
|
46
|
+
return "unknown";
|
|
47
|
+
try {
|
|
48
|
+
const parsed = JSON.parse(payload);
|
|
49
|
+
return parsed.jobName ?? parsed.name ?? "unknown";
|
|
50
|
+
} catch {
|
|
51
|
+
return "unknown";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function formatUnixTime(seconds) {
|
|
55
|
+
if (typeof seconds !== "number" || !Number.isFinite(seconds))
|
|
56
|
+
return "N/A";
|
|
57
|
+
return new Date(seconds * 1000).toISOString().slice(0, 19).replace("T", " ");
|
|
58
|
+
}
|
|
59
|
+
function parseArgs() {
|
|
60
|
+
const args = {};
|
|
61
|
+
process.argv.forEach((arg) => {
|
|
62
|
+
if (arg.startsWith("--")) {
|
|
63
|
+
const [key, value] = arg.slice(2).split("=");
|
|
64
|
+
if (key && value)
|
|
65
|
+
args[key] = value;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return args;
|
|
69
|
+
}
|