@merittdev/horus 0.1.8 → 0.1.10
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/index.cjs +68 -15
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -50314,7 +50314,7 @@ init_cjs_shims();
|
|
|
50314
50314
|
|
|
50315
50315
|
// ../../packages/core/src/version.ts
|
|
50316
50316
|
init_cjs_shims();
|
|
50317
|
-
var HORUS_VERSION = true ? "0.1.
|
|
50317
|
+
var HORUS_VERSION = true ? "0.1.10" : "dev";
|
|
50318
50318
|
var PINNED_AXON_VERSION = "1.0.7";
|
|
50319
50319
|
var PINNED_SOURCE_VERSION = PINNED_AXON_VERSION;
|
|
50320
50320
|
|
|
@@ -57084,12 +57084,16 @@ var BullMQRedisClient = class {
|
|
|
57084
57084
|
);
|
|
57085
57085
|
}
|
|
57086
57086
|
/**
|
|
57087
|
-
* Discover queue names by scanning for BullMQ
|
|
57087
|
+
* Discover queue names by scanning for BullMQ `:meta` keys.
|
|
57088
|
+
*
|
|
57089
|
+
* `:meta` is written when a Queue is instantiated and persists regardless of job
|
|
57090
|
+
* state, so it finds idle queues too. Scanning `:wait` (the previous approach) only
|
|
57091
|
+
* surfaced queues with pending jobs, so idle-but-real queues were invisible.
|
|
57088
57092
|
* Returns at most `limit` queue names.
|
|
57089
57093
|
*/
|
|
57090
57094
|
async discoverQueues(limit = 50) {
|
|
57091
|
-
const pattern = `${this.prefix}:*:
|
|
57092
|
-
const suffixLen = ":
|
|
57095
|
+
const pattern = `${this.prefix}:*:meta`;
|
|
57096
|
+
const suffixLen = ":meta".length;
|
|
57093
57097
|
const prefixLen = this.prefix.length + 1;
|
|
57094
57098
|
const names = [];
|
|
57095
57099
|
let cursor = "0";
|
|
@@ -57272,6 +57276,10 @@ var BullMQRuntimeProvider = class {
|
|
|
57272
57276
|
const queues = await Promise.all(names.map((name) => this.inspectQueue(name)));
|
|
57273
57277
|
return { prefix: this.client.prefix, collectedAt, queues };
|
|
57274
57278
|
}
|
|
57279
|
+
/** Discover queue names present in Redis under the configured prefix. */
|
|
57280
|
+
discoverQueues() {
|
|
57281
|
+
return this.client.discoverQueues();
|
|
57282
|
+
}
|
|
57275
57283
|
async inspectQueue(name) {
|
|
57276
57284
|
const [waiting, active, failed, delayed, completed, paused] = await Promise.all([
|
|
57277
57285
|
this.client.listLen(this.client.queueKey(name, "wait")),
|
|
@@ -66795,9 +66803,37 @@ async function checkEnv(renv, deps) {
|
|
|
66795
66803
|
const redisCfg = renv.connectors.redis;
|
|
66796
66804
|
if (redisCfg?.url) {
|
|
66797
66805
|
const safeUrl = redactRedisUrl(redisCfg.url);
|
|
66798
|
-
|
|
66799
|
-
|
|
66800
|
-
|
|
66806
|
+
const queueProvider = (deps?.queueFactory ?? queueForEnv)(renv);
|
|
66807
|
+
if (queueProvider) {
|
|
66808
|
+
try {
|
|
66809
|
+
const h = await queueProvider.health();
|
|
66810
|
+
if (h.ok) {
|
|
66811
|
+
let queueInfo = "";
|
|
66812
|
+
try {
|
|
66813
|
+
const discovered = await queueProvider.discoverQueues();
|
|
66814
|
+
queueInfo = ` \xB7 ${discovered.length} queue(s)`;
|
|
66815
|
+
} catch {
|
|
66816
|
+
}
|
|
66817
|
+
console.log(
|
|
66818
|
+
` ${mark(true)} ${import_picocolors.default.bold("Redis")} ${import_picocolors.default.dim(`reachable \xB7 ${safeUrl}${queueInfo}`)}`
|
|
66819
|
+
);
|
|
66820
|
+
} else {
|
|
66821
|
+
const authFailed = /WRONGPASS|NOAUTH|invalid password/i.test(h.detail);
|
|
66822
|
+
const state = authFailed ? "auth failed" : "unreachable";
|
|
66823
|
+
console.log(
|
|
66824
|
+
` ${mark(false)} ${import_picocolors.default.bold("Redis")} ${import_picocolors.default.dim(`${state} \xB7 ${safeUrl} \xB7 ${h.detail}`)}`
|
|
66825
|
+
);
|
|
66826
|
+
allOk = false;
|
|
66827
|
+
}
|
|
66828
|
+
} finally {
|
|
66829
|
+
await queueProvider.close().catch(() => {
|
|
66830
|
+
});
|
|
66831
|
+
}
|
|
66832
|
+
} else {
|
|
66833
|
+
console.log(
|
|
66834
|
+
` ${mark("pending")} ${import_picocolors.default.bold("Redis")} ${import_picocolors.default.dim(`configured \xB7 ${safeUrl}`)}`
|
|
66835
|
+
);
|
|
66836
|
+
}
|
|
66801
66837
|
} else {
|
|
66802
66838
|
console.log(
|
|
66803
66839
|
` ${mark("pending")} ${import_picocolors.default.bold("Redis")} ${import_picocolors.default.dim("not configured")}`
|
|
@@ -66869,7 +66905,7 @@ Horus ${HORUS_VERSION}`));
|
|
|
66869
66905
|
console.error(import_picocolors.default.red(err.message));
|
|
66870
66906
|
return 1;
|
|
66871
66907
|
}
|
|
66872
|
-
const ok = await checkEnv(renv, { mongoFactory: opts?._mongoFactory });
|
|
66908
|
+
const ok = await checkEnv(renv, { mongoFactory: opts?._mongoFactory, queueFactory: opts?._queueFactory });
|
|
66873
66909
|
return ok ? 0 : 1;
|
|
66874
66910
|
}
|
|
66875
66911
|
let allHealthy = true;
|
|
@@ -66882,7 +66918,7 @@ Horus ${HORUS_VERSION}`));
|
|
|
66882
66918
|
allHealthy = false;
|
|
66883
66919
|
continue;
|
|
66884
66920
|
}
|
|
66885
|
-
const ok = await checkEnv(renv, { mongoFactory: opts?._mongoFactory });
|
|
66921
|
+
const ok = await checkEnv(renv, { mongoFactory: opts?._mongoFactory, queueFactory: opts?._queueFactory });
|
|
66886
66922
|
if (!ok) allHealthy = false;
|
|
66887
66923
|
}
|
|
66888
66924
|
return checks.some((c) => c.ok === false && c.fatal) ? 1 : 0;
|
|
@@ -67311,7 +67347,7 @@ async function runIndex(opts) {
|
|
|
67311
67347
|
` investigate: horus investigate --name ${name} "<hint>" (or from this repo: horus investigate "<hint>")`
|
|
67312
67348
|
)
|
|
67313
67349
|
);
|
|
67314
|
-
} else if (
|
|
67350
|
+
} else if (hostUrl !== configuredHost) {
|
|
67315
67351
|
const existingPath = discoverLocalConfig(root);
|
|
67316
67352
|
if (existingPath) {
|
|
67317
67353
|
const file = readLocalConfig(existingPath);
|
|
@@ -67348,7 +67384,14 @@ async function runQueues(name, opts) {
|
|
|
67348
67384
|
const config = await loadConfig(opts.config, { name: opts.name });
|
|
67349
67385
|
const { db, sql: sql2 } = createDb(config.database.url);
|
|
67350
67386
|
try {
|
|
67351
|
-
|
|
67387
|
+
let project = opts.project;
|
|
67388
|
+
if (project === void 0) {
|
|
67389
|
+
try {
|
|
67390
|
+
project = resolveEnvironment(config, { project: opts.project }).project;
|
|
67391
|
+
} catch {
|
|
67392
|
+
}
|
|
67393
|
+
}
|
|
67394
|
+
const rows = await listQueueEdges(db, { project, queueName: name });
|
|
67352
67395
|
console.log(
|
|
67353
67396
|
import_picocolors4.default.bold("Queue topology") + import_picocolors4.default.dim(" \xB7 source: code / source intelligence \xB7 static (run horus index to refresh)")
|
|
67354
67397
|
);
|
|
@@ -67455,8 +67498,15 @@ async function runLiveMode(config, rows, nameFilter) {
|
|
|
67455
67498
|
console.log(import_picocolors4.default.red(` \u2717 Redis unreachable: ${health.detail}`));
|
|
67456
67499
|
return;
|
|
67457
67500
|
}
|
|
67458
|
-
const
|
|
67459
|
-
|
|
67501
|
+
const staticNames = new Set(buildQueueMap(rows).keys());
|
|
67502
|
+
let queueNames;
|
|
67503
|
+
if (nameFilter !== void 0) {
|
|
67504
|
+
queueNames = [nameFilter];
|
|
67505
|
+
} else {
|
|
67506
|
+
const discovered = await queueProvider.discoverQueues().catch(() => []);
|
|
67507
|
+
const union2 = /* @__PURE__ */ new Set([...staticNames, ...discovered]);
|
|
67508
|
+
queueNames = union2.size > 0 ? [...union2] : void 0;
|
|
67509
|
+
}
|
|
67460
67510
|
const state = await queueProvider.analyzeQueues({ queueNames });
|
|
67461
67511
|
const collectedAt = new Date(state.collectedAt).toLocaleTimeString();
|
|
67462
67512
|
console.log(
|
|
@@ -67473,7 +67523,7 @@ async function runLiveMode(config, rows, nameFilter) {
|
|
|
67473
67523
|
);
|
|
67474
67524
|
return;
|
|
67475
67525
|
}
|
|
67476
|
-
printLiveTable(state.queues);
|
|
67526
|
+
printLiveTable(state.queues, staticNames);
|
|
67477
67527
|
} catch (err) {
|
|
67478
67528
|
if (!headerPrinted) {
|
|
67479
67529
|
console.log(import_picocolors4.default.bold("Live queue state") + import_picocolors4.default.dim(" \xB7 source: Redis/BullMQ"));
|
|
@@ -67484,7 +67534,7 @@ async function runLiveMode(config, rows, nameFilter) {
|
|
|
67484
67534
|
});
|
|
67485
67535
|
}
|
|
67486
67536
|
}
|
|
67487
|
-
function printLiveTable(queues) {
|
|
67537
|
+
function printLiveTable(queues, staticNames = /* @__PURE__ */ new Set()) {
|
|
67488
67538
|
const nameWidth = Math.max(10, ...queues.map((q) => q.queueName.length));
|
|
67489
67539
|
const numWidth = 7;
|
|
67490
67540
|
const header = " " + "queue".padEnd(nameWidth) + " " + "waiting".padStart(numWidth) + " " + "active".padStart(numWidth) + " " + "failed".padStart(numWidth) + " " + "delayed".padStart(numWidth) + " " + "paused".padStart(numWidth);
|
|
@@ -67495,6 +67545,9 @@ function printLiveTable(queues) {
|
|
|
67495
67545
|
const color = hasIssue ? import_picocolors4.default.yellow : (s) => s;
|
|
67496
67546
|
const row = " " + q.queueName.padEnd(nameWidth) + " " + String(q.waiting).padStart(numWidth) + " " + String(q.active).padStart(numWidth) + " " + String(q.failed).padStart(numWidth) + " " + String(q.delayed).padStart(numWidth) + " " + (q.isPaused ? import_picocolors4.default.yellow("paused") : String(q.paused).padStart(numWidth));
|
|
67497
67547
|
console.log(color(row));
|
|
67548
|
+
if (!staticNames.has(q.queueName)) {
|
|
67549
|
+
console.log(import_picocolors4.default.dim(" runtime-only \xB7 no static producer/worker mapping"));
|
|
67550
|
+
}
|
|
67498
67551
|
if (q.oldestWaitingMs !== void 0) {
|
|
67499
67552
|
const age = formatAge(q.oldestWaitingMs);
|
|
67500
67553
|
console.log(import_picocolors4.default.dim(` oldest waiting: ${age}`));
|