@rudderjs/horizon 4.1.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,7 +24,7 @@ import { Horizon } from '@rudderjs/horizon'
24
24
 
25
25
  const jobs = await Horizon.recentJobs({ queue: 'emails', perPage: 25 })
26
26
  const failed = await Horizon.failedJobs()
27
- const job = await Horizon.findJob('job-id')
27
+ const job = await Horizon.findJob('emails', 'job-id')
28
28
  const metrics = await Horizon.currentMetrics()
29
29
  const workers = await Horizon.workers()
30
30
  const count = await Horizon.jobCount('failed')
@@ -36,7 +36,7 @@ const count = await Horizon.jobCount('failed')
36
36
  |--------|---------|-------------|
37
37
  | `recentJobs(options?)` | `HorizonJob[]` | List recent jobs with optional filters |
38
38
  | `failedJobs(options?)` | `HorizonJob[]` | List failed jobs |
39
- | `findJob(id)` | `HorizonJob \| null` | Find a single job by ID |
39
+ | `findJob(queue, id)` | `HorizonJob \| null` | Find a single job by `(queue, id)` — BullMQ ids are per-queue |
40
40
  | `currentMetrics()` | `QueueMetric[]` | Latest metric snapshot per queue |
41
41
  | `workers()` | `WorkerInfo[]` | All known workers and their status |
42
42
  | `jobCount(status?)` | `number` | Count jobs, optionally by status |
@@ -85,3 +85,4 @@ Horizon serves a built-in UI at `/{path}` with pages for:
85
85
  - Requires `@rudderjs/queue` for job lifecycle hooks.
86
86
  - Peers: `@rudderjs/router` and `@rudderjs/middleware` for route registration.
87
87
  - Auto-prune runs on a background interval (does not block the event loop).
88
+ - With BullMQ, `MetricsCollector` only registers in the worker process (set `RUDDERJS_QUEUE_WORKER=1` — `pnpm rudder queue:work` does this for you). The dashboard process serves `/horizon/api/queues` from the worker's last write. If the worker is offline the metrics tile freezes; jobs and failed tabs continue to work because they read live state from BullMQ.
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAErF,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAa,MAAM,aAAa,CAAA;AAQ3E,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAK,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,EACvB,GAAG,EAAM,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,EACvB,GAAG,EAAM,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAsB,OAAO,CAC3B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAM,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAM,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAM,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,wBAAsB,UAAU,CAC9B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAK,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAM,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAK,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAGf;AAID,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,iBAAiB,CAWrF"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAErF,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAa,MAAM,aAAa,CAAA;AAQ3E,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAK,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,EACvB,GAAG,EAAM,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,EACvB,GAAG,EAAM,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAsB,OAAO,CAC3B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAM,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAM,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAM,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAsB,UAAU,CAC9B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAK,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAM,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,cAAc,EACvB,IAAI,EAAK,UAAU,EACnB,GAAG,EAAM,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAGf;AAID,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,iBAAiB,CAWrF"}
@@ -42,7 +42,9 @@ export async function listFailedJobs(storage, req, res) {
42
42
  res.json({ data: jobs, meta: { total } });
43
43
  }
44
44
  export async function showJob(storage, req, res) {
45
- const job = await storage.findJob(req.params['id'] ?? '');
45
+ const queue = req.params['queue'] ?? '';
46
+ const id = req.params['id'] ?? '';
47
+ const job = await storage.findJob(queue, id);
46
48
  if (!job) {
47
49
  res.status(404).json({ message: 'Job not found.' });
48
50
  return;
@@ -50,7 +52,9 @@ export async function showJob(storage, req, res) {
50
52
  res.json({ data: job });
51
53
  }
52
54
  export async function retryJob(storage, req, res) {
53
- const job = await storage.findJob(req.params['id'] ?? '');
55
+ const queue = req.params['queue'] ?? '';
56
+ const id = req.params['id'] ?? '';
57
+ const job = await storage.findJob(queue, id);
54
58
  if (!job) {
55
59
  res.status(404).json({ message: 'Job not found.' });
56
60
  return;
@@ -62,7 +66,7 @@ export async function retryJob(storage, req, res) {
62
66
  const adapter = QueueRegistry.get();
63
67
  if (adapter?.retryFailed) {
64
68
  await adapter.retryFailed(job.queue);
65
- storage.updateJob(job.id, { status: 'pending', exception: null });
69
+ storage.updateJob(job.queue, job.id, { status: 'pending', exception: null });
66
70
  res.json({ message: 'Job queued for retry.' });
67
71
  }
68
72
  else {
@@ -70,12 +74,14 @@ export async function retryJob(storage, req, res) {
70
74
  }
71
75
  }
72
76
  export async function deleteJob(storage, req, res) {
73
- const job = await storage.findJob(req.params['id'] ?? '');
77
+ const queue = req.params['queue'] ?? '';
78
+ const id = req.params['id'] ?? '';
79
+ const job = await storage.findJob(queue, id);
74
80
  if (!job) {
75
81
  res.status(404).json({ message: 'Job not found.' });
76
82
  return;
77
83
  }
78
- storage.deleteJob(job.id);
84
+ storage.deleteJob(job.queue, job.id);
79
85
  res.json({ message: 'Job deleted.' });
80
86
  }
81
87
  export async function listQueues(storage, _req, res) {
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/api/routes.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,24 @@
1
1
  import type { HorizonStorage } from '../types.js';
2
+ import type { MetricsCollector } from './metrics.js';
2
3
  /**
3
- * Intercepts job dispatch and execution to record full job lifecycle.
4
- * Wraps the QueueAdapter to capture dispatch, start, completion, and failure events.
4
+ * Subscribes to `@rudderjs/queue/observers` and forwards lifecycle events
5
+ * into Horizon's storage. Replaces the legacy `dispatch()` monkey-patch
6
+ * which couldn't see worker-process events under BullMQ.
7
+ *
8
+ * The previous monkey-patch wrapped `job.handle` on an in-memory instance
9
+ * the worker process never received via Redis — so worker-side
10
+ * completed/failed transitions were lost. The observer surface emits in
11
+ * the worker process, RedisStorage propagates the writes back to the
12
+ * dashboard process. See `docs/plans/2026-05-01-horizon-bullmq-fix.md`.
5
13
  */
6
14
  export declare class JobCollector {
7
15
  private readonly storage;
16
+ private readonly metricsCollector;
8
17
  readonly name = "Job Collector";
9
- constructor(storage: HorizonStorage);
18
+ private unsubscribe;
19
+ constructor(storage: HorizonStorage, metricsCollector?: MetricsCollector | null);
10
20
  register(): void;
21
+ /** @internal — used in tests + provider shutdown. */
22
+ unregister(): void;
11
23
  }
12
24
  //# sourceMappingURL=job.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../../src/collectors/job.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,aAAa,CAAA;AAE7D;;;GAGG;AACH,qBAAa,YAAY;IAGX,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,QAAQ,CAAC,IAAI,mBAAkB;gBAEF,OAAO,EAAE,cAAc;IAEpD,QAAQ,IAAI,IAAI;CAwEjB"}
1
+ {"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../../src/collectors/job.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,aAAa,CAAA;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAEpD;;;;;;;;;;GAUG;AACH,qBAAa,YAAY;IAKrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IALnC,QAAQ,CAAC,IAAI,mBAAkB;IAC/B,OAAO,CAAC,WAAW,CAA4B;gBAG5B,OAAO,EAAW,cAAc,EAChC,gBAAgB,GAAE,gBAAgB,GAAG,IAAW;IAGnE,QAAQ,IAAI,IAAI;IA4DhB,qDAAqD;IACrD,UAAU,IAAI,IAAI;CAInB"}
@@ -1,85 +1,84 @@
1
- import { randomUUID } from 'node:crypto';
2
- import { QueueRegistry } from '@rudderjs/queue';
1
+ import { queueObservers } from '@rudderjs/queue/observers';
3
2
  /**
4
- * Intercepts job dispatch and execution to record full job lifecycle.
5
- * Wraps the QueueAdapter to capture dispatch, start, completion, and failure events.
3
+ * Subscribes to `@rudderjs/queue/observers` and forwards lifecycle events
4
+ * into Horizon's storage. Replaces the legacy `dispatch()` monkey-patch
5
+ * which couldn't see worker-process events under BullMQ.
6
+ *
7
+ * The previous monkey-patch wrapped `job.handle` on an in-memory instance
8
+ * the worker process never received via Redis — so worker-side
9
+ * completed/failed transitions were lost. The observer surface emits in
10
+ * the worker process, RedisStorage propagates the writes back to the
11
+ * dashboard process. See `docs/plans/2026-05-01-horizon-bullmq-fix.md`.
6
12
  */
7
13
  export class JobCollector {
8
14
  storage;
15
+ metricsCollector;
9
16
  name = 'Job Collector';
10
- constructor(storage) {
17
+ unsubscribe = null;
18
+ constructor(storage, metricsCollector = null) {
11
19
  this.storage = storage;
20
+ this.metricsCollector = metricsCollector;
12
21
  }
13
22
  register() {
14
- const adapter = QueueRegistry.get();
15
- if (!adapter)
16
- return;
17
- const storage = this.storage;
18
- const originalDispatch = adapter.dispatch.bind(adapter);
19
- adapter['dispatch'] = async (job, options) => {
20
- const id = randomUUID();
21
- const name = job.constructor.name;
22
- const queue = options?.queue ?? job.constructor['queue'] ?? 'default';
23
- const now = new Date();
24
- // Record dispatch
25
- const record = {
26
- id,
27
- name,
28
- queue,
29
- status: 'pending',
30
- payload: safeSerialize(job),
31
- attempts: 0,
32
- exception: null,
33
- dispatchedAt: now,
34
- startedAt: null,
35
- completedAt: null,
36
- duration: null,
37
- tags: [`job:${name}`, `queue:${queue}`],
38
- };
39
- storage.recordJob(record);
40
- // Track start/complete/fail via wrapping the job's handle method
41
- const originalHandle = job.handle.bind(job);
42
- const originalFailed = job.failed?.bind(job);
43
- job.handle = async () => {
44
- const startedAt = new Date();
45
- storage.updateJob(id, { status: 'processing', startedAt, attempts: record.attempts + 1 });
23
+ this.unsubscribe = queueObservers.subscribe((event) => {
24
+ // Storage writes can be async (Redis); fire-and-forget but trap rejects
25
+ // so a transient Redis blip never escapes into the queue layer.
26
+ void Promise.resolve().then(async () => {
46
27
  try {
47
- await originalHandle();
48
- const completedAt = new Date();
49
- const duration = completedAt.getTime() - startedAt.getTime();
50
- storage.updateJob(id, { status: 'completed', completedAt, duration });
28
+ switch (event.kind) {
29
+ case 'job.dispatched': {
30
+ const record = {
31
+ id: event.jobId,
32
+ name: event.name,
33
+ queue: event.queue,
34
+ status: 'pending',
35
+ payload: event.payload,
36
+ attempts: 0,
37
+ exception: null,
38
+ dispatchedAt: event.dispatchedAt,
39
+ startedAt: null,
40
+ completedAt: null,
41
+ duration: null,
42
+ tags: [`job:${event.name}`, `queue:${event.queue}`],
43
+ };
44
+ await this.storage.recordJob(record);
45
+ break;
46
+ }
47
+ case 'job.active':
48
+ await this.storage.updateJob(event.queue, event.jobId, {
49
+ status: 'processing',
50
+ startedAt: event.startedAt,
51
+ attempts: event.attempts,
52
+ });
53
+ break;
54
+ case 'job.completed':
55
+ await this.storage.updateJob(event.queue, event.jobId, {
56
+ status: 'completed',
57
+ completedAt: event.completedAt,
58
+ duration: event.duration,
59
+ });
60
+ this.metricsCollector?.recordJobCompleted(event.queue, event.startedAt.getTime() - event.dispatchedAt.getTime(), event.duration);
61
+ break;
62
+ case 'job.failed':
63
+ await this.storage.updateJob(event.queue, event.jobId, {
64
+ status: 'failed',
65
+ completedAt: event.completedAt,
66
+ ...(event.duration !== undefined ? { duration: event.duration } : {}),
67
+ exception: event.error,
68
+ });
69
+ break;
70
+ }
51
71
  }
52
72
  catch (err) {
53
- const completedAt = new Date();
54
- const duration = completedAt.getTime() - startedAt.getTime();
55
- storage.updateJob(id, {
56
- status: 'failed',
57
- completedAt,
58
- duration,
59
- exception: err instanceof Error ? err.message : String(err),
60
- });
61
- throw err;
73
+ console.warn('[Horizon] storage write failed:', err instanceof Error ? err.message : String(err));
62
74
  }
63
- };
64
- if (originalFailed) {
65
- job.failed = async (error) => {
66
- storage.updateJob(id, {
67
- status: 'failed',
68
- exception: error instanceof Error ? error.message : String(error),
69
- });
70
- await originalFailed(error);
71
- };
72
- }
73
- await originalDispatch(job, options);
74
- };
75
+ });
76
+ });
75
77
  }
76
- }
77
- function safeSerialize(obj) {
78
- try {
79
- return JSON.parse(JSON.stringify(obj));
80
- }
81
- catch {
82
- return {};
78
+ /** @internal — used in tests + provider shutdown. */
79
+ unregister() {
80
+ this.unsubscribe?.();
81
+ this.unsubscribe = null;
83
82
  }
84
83
  }
85
84
  //# sourceMappingURL=job.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"job.js","sourceRoot":"","sources":["../../src/collectors/job.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"job.js","sourceRoot":"","sources":["../../src/collectors/job.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/collectors/worker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,aAAa,CAAA;AAE7D;;;GAGG;AACH,qBAAa,eAAe;IAOxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAPxB,QAAQ,CAAC,IAAI,sBAAqB;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,OAAO,CAAI;IACnB,OAAO,CAAC,SAAS,CAAoB;gBAGlB,OAAO,EAAE,cAAc,EACvB,KAAK,GAAE,MAAkB;IAK5C,QAAQ,IAAI,IAAI;IAShB,kDAAkD;IAClD,kBAAkB,IAAI,IAAI;IAK1B,OAAO,CAAC,MAAM;CAaf"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/collectors/worker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,aAAa,CAAA;AAE7D;;;GAGG;AACH,qBAAa,eAAe;IAOxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK;IAPxB,QAAQ,CAAC,IAAI,sBAAqB;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,OAAO,CAAI;IACnB,OAAO,CAAC,SAAS,CAAoB;gBAGlB,OAAO,EAAE,cAAc,EACvB,KAAK,GAAE,MAAkB;IAK5C,QAAQ,IAAI,IAAI;IAehB,kDAAkD;IAClD,kBAAkB,IAAI,IAAI;IAK1B,OAAO,CAAC,MAAM;CAaf"}
@@ -16,6 +16,12 @@ export class WorkerCollector {
16
16
  this.workerId = `worker-${randomUUID().slice(0, 8)}`;
17
17
  }
18
18
  register() {
19
+ // Only register as a worker when running in an actual worker process.
20
+ // Set by `@rudderjs/queue-bullmq` (and any future self-hosted adapter)
21
+ // before booting `Worker` instances. Skipping in the dev/web process
22
+ // prevents the dashboard from listing itself as a worker.
23
+ if (process.env['RUDDERJS_QUEUE_WORKER'] !== '1')
24
+ return;
19
25
  // Report initial status
20
26
  this.report('active');
21
27
  // Periodically update
@@ -1 +1 @@
1
- {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/collectors/worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAGxC;;;GAGG;AACH,MAAM,OAAO,eAAe;IAOP;IACA;IAPV,IAAI,GAAG,kBAAkB,CAAA;IACjB,QAAQ,CAAQ;IACzB,OAAO,GAAG,CAAC,CAAA;IACX,SAAS,GAAgB,IAAI,CAAA;IAErC,YACmB,OAAuB,EACvB,QAAgB,SAAS;QADzB,YAAO,GAAP,OAAO,CAAgB;QACvB,UAAK,GAAL,KAAK,CAAoB;QAE1C,IAAI,CAAC,QAAQ,GAAG,UAAU,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;IACtD,CAAC;IAED,QAAQ;QACN,wBAAwB;QACxB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QAErB,sBAAsB;QACtB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAA;QAC9D,KAAK,CAAC,KAAK,EAAE,CAAA;IACf,CAAC;IAED,kDAAkD;IAClD,kBAAkB;QAChB,IAAI,CAAC,OAAO,EAAE,CAAA;QACd,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAA;IAC7B,CAAC;IAEO,MAAM,CAAC,MAA4B;QACzC,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,CAAA;QACtC,MAAM,IAAI,GAAe;YACvB,EAAE,EAAS,IAAI,CAAC,QAAQ;YACxB,KAAK,EAAM,IAAI,CAAC,KAAK;YACrB,MAAM;YACN,OAAO,EAAI,IAAI,CAAC,OAAO;YACvB,QAAQ,EAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG;YACpE,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAA;QACD,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;CACF"}
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/collectors/worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAGxC;;;GAGG;AACH,MAAM,OAAO,eAAe;IAOP;IACA;IAPV,IAAI,GAAG,kBAAkB,CAAA;IACjB,QAAQ,CAAQ;IACzB,OAAO,GAAG,CAAC,CAAA;IACX,SAAS,GAAgB,IAAI,CAAA;IAErC,YACmB,OAAuB,EACvB,QAAgB,SAAS;QADzB,YAAO,GAAP,OAAO,CAAgB;QACvB,UAAK,GAAL,KAAK,CAAoB;QAE1C,IAAI,CAAC,QAAQ,GAAG,UAAU,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;IACtD,CAAC;IAED,QAAQ;QACN,sEAAsE;QACtE,uEAAuE;QACvE,qEAAqE;QACrE,0DAA0D;QAC1D,IAAI,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,KAAK,GAAG;YAAE,OAAM;QAExD,wBAAwB;QACxB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QAErB,sBAAsB;QACtB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAA;QAC9D,KAAK,CAAC,KAAK,EAAE,CAAA;IACf,CAAC;IAED,kDAAkD;IAClD,kBAAkB;QAChB,IAAI,CAAC,OAAO,EAAE,CAAA;QACd,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAA;IAC7B,CAAC;IAEO,MAAM,CAAC,MAA4B;QACzC,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,CAAA;QACtC,MAAM,IAAI,GAAe;YACvB,EAAE,EAAS,IAAI,CAAC,QAAQ;YACxB,KAAK,EAAM,IAAI,CAAC,KAAK;YACrB,MAAM;YACN,OAAO,EAAI,IAAI,CAAC,OAAO;YACvB,QAAQ,EAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG;YACpE,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAA;QACD,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IACjC,CAAC;CACF"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ServiceProvider } from '@rudderjs/core';
2
- import { type HorizonConfig, type HorizonStorage, type HorizonJob, type QueueMetric, type WorkerInfo, type JobStatus, type JobListOptions } from './types.js';
3
- export type { HorizonConfig, HorizonStorage, HorizonJob, QueueMetric, WorkerInfo, JobStatus, JobListOptions };
4
- export { MemoryStorage, SqliteStorage } from './storage.js';
2
+ import { type HorizonConfig, type HorizonStorage, type HorizonJob, type QueueMetric, type WorkerInfo, type JobStatus, type JobListOptions, type HorizonRedisConfig } from './types.js';
3
+ export type { HorizonConfig, HorizonStorage, HorizonJob, QueueMetric, WorkerInfo, JobStatus, JobListOptions, HorizonRedisConfig };
4
+ export { MemoryStorage, SqliteStorage, RedisStorage } from './storage.js';
5
5
  export { JobCollector } from './collectors/job.js';
6
6
  export { MetricsCollector } from './collectors/metrics.js';
7
7
  export { WorkerCollector } from './collectors/worker.js';
@@ -16,7 +16,7 @@ export declare class Horizon {
16
16
  private static store;
17
17
  static recentJobs(options?: JobListOptions): HorizonJob[] | Promise<HorizonJob[]>;
18
18
  static failedJobs(options?: JobListOptions): HorizonJob[] | Promise<HorizonJob[]>;
19
- static findJob(id: string): HorizonJob | null | Promise<HorizonJob | null>;
19
+ static findJob(queue: string, id: string): HorizonJob | null | Promise<HorizonJob | null>;
20
20
  static currentMetrics(): QueueMetric[] | Promise<QueueMetric[]>;
21
21
  static workers(): WorkerInfo[] | Promise<WorkerInfo[]>;
22
22
  static jobCount(status?: JobStatus): number | Promise<number>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAU,MAAM,gBAAgB,CAAA;AAMxD,OAAO,EAEL,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EACxD,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,cAAc,EACvE,MAAM,YAAY,CAAA;AAInB,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,CAAA;AAC7G,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAIxD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,OAAO,CAA8B;IAEpD,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IACzC,MAAM,CAAC,GAAG,IAAI,cAAc,GAAG,IAAI;IACnC,mEAAmE;IACnE,MAAM,CAAC,KAAK,IAAI,IAAI;CACrB;AAID,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAAC,KAAK;IAMpB,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAIjF,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAIjF,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAI1E,MAAM,CAAC,cAAc,IAAI,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAI/D,MAAM,CAAC,OAAO,IAAI,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAItD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAG9D;AAID;;;;;;;;;;GAUG;AACH,qBAAa,eAAgB,SAAQ,eAAe;IAClD,QAAQ,IAAI,IAAI;IAQV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAoD5B;AAID,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAU,MAAM,gBAAgB,CAAA;AAMxD,OAAO,EAEL,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EACxD,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,KAAK,cAAc,EACtE,KAAK,kBAAkB,EACxB,MAAM,YAAY,CAAA;AAInB,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAA;AACjI,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAIxD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,OAAO,CAA8B;IAEpD,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IACzC,MAAM,CAAC,GAAG,IAAI,cAAc,GAAG,IAAI;IACnC,mEAAmE;IACnE,MAAM,CAAC,KAAK,IAAI,IAAI;CACrB;AAID,qBAAa,OAAO;IAClB,OAAO,CAAC,MAAM,CAAC,KAAK;IAMpB,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAIjF,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAIjF,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAIzF,MAAM,CAAC,cAAc,IAAI,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAI/D,MAAM,CAAC,OAAO,IAAI,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAItD,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAG9D;AAID;;;;;;;;;;GAUG;AACH,qBAAa,eAAgB,SAAQ,eAAe;IAClD,QAAQ,IAAI,IAAI;IAQV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAoF5B;AAID,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,MAAM,aAAa,CAAA"}
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { ServiceProvider, config } from '@rudderjs/core';
2
- import { MemoryStorage, SqliteStorage } from './storage.js';
2
+ import { MemoryStorage, SqliteStorage, RedisStorage } from './storage.js';
3
3
  import { JobCollector } from './collectors/job.js';
4
4
  import { MetricsCollector } from './collectors/metrics.js';
5
5
  import { WorkerCollector } from './collectors/worker.js';
6
6
  import { registerHorizonRoutes } from './routes.js';
7
7
  import { defaultConfig, } from './types.js';
8
- export { MemoryStorage, SqliteStorage } from './storage.js';
8
+ export { MemoryStorage, SqliteStorage, RedisStorage } from './storage.js';
9
9
  export { JobCollector } from './collectors/job.js';
10
10
  export { MetricsCollector } from './collectors/metrics.js';
11
11
  export { WorkerCollector } from './collectors/worker.js';
@@ -31,8 +31,8 @@ export class Horizon {
31
31
  static failedJobs(options) {
32
32
  return this.store().failedJobs(options);
33
33
  }
34
- static findJob(id) {
35
- return this.store().findJob(id);
34
+ static findJob(queue, id) {
35
+ return this.store().findJob(queue, id);
36
36
  }
37
37
  static currentMetrics() {
38
38
  return this.store().currentMetrics();
@@ -83,11 +83,29 @@ export class HorizonProvider extends ServiceProvider {
83
83
  if (resolved.storage === 'sqlite') {
84
84
  storage = new SqliteStorage(resolved.sqlitePath);
85
85
  }
86
+ else if (resolved.storage === 'redis') {
87
+ const redisCfg = (cfg.redis ?? defaultConfig.redis);
88
+ storage = new RedisStorage(redisCfg, resolved.maxJobs);
89
+ }
86
90
  else {
87
91
  storage = new MemoryStorage(resolved.maxJobs);
88
92
  }
89
93
  HorizonRegistry.set(storage);
90
94
  this.app.instance('horizon', storage);
95
+ // ── Misconfig warning ─────────────────────────────────
96
+ // BullMQ runs jobs in a separate process; with in-memory storage the
97
+ // dashboard can't see the worker-process state transitions and every
98
+ // job appears stuck at 'pending' forever. Surface this loudly so users
99
+ // catch it before they're staring at a dead dashboard.
100
+ try {
101
+ const queueDriver = config('queue', {})?.default;
102
+ if (queueDriver === 'bullmq' && resolved.storage === 'memory') {
103
+ console.warn('[Horizon] queue driver "bullmq" is paired with horizon storage "memory" — ' +
104
+ 'the dashboard will not see worker-process events (jobs will appear stuck at pending). ' +
105
+ "Set horizon.storage = 'redis' in config/horizon.ts to fix this.");
106
+ }
107
+ }
108
+ catch { /* config read failure shouldn't block boot */ }
91
109
  // ── Auto-prune ────────────────────────────────────────
92
110
  const pruneHours = resolved.pruneAfterHours;
93
111
  if (pruneHours > 0) {
@@ -98,11 +116,29 @@ export class HorizonProvider extends ServiceProvider {
98
116
  timer.unref();
99
117
  }
100
118
  // ── Register collectors ───────────────────────────────
101
- const jobCollector = new JobCollector(storage);
102
119
  const metricsCollector = new MetricsCollector(storage, resolved.metricsIntervalMs);
120
+ const jobCollector = new JobCollector(storage, metricsCollector);
103
121
  const workerCollector = new WorkerCollector(storage);
104
122
  jobCollector.register();
105
- metricsCollector.register();
123
+ // For out-of-process queues (BullMQ), `queueObservers` events fire in
124
+ // the worker process, not the dashboard. Letting both processes poll
125
+ // `MetricsCollector.collect()` makes the dashboard write
126
+ // `throughput: 0` rows that clobber the worker's real counts via the
127
+ // shared Redis history ZSet. Gate to the worker process. Sync queue
128
+ // is in-process — dashboard IS the worker, so we let it through.
129
+ const queueDriver = (() => {
130
+ try {
131
+ return config('queue', {})?.default;
132
+ }
133
+ catch {
134
+ return undefined;
135
+ }
136
+ })();
137
+ const outOfProcessQueue = queueDriver === 'bullmq';
138
+ const isWorkerProcess = process.env['RUDDERJS_QUEUE_WORKER'] === '1';
139
+ if (!outOfProcessQueue || isWorkerProcess) {
140
+ metricsCollector.register();
141
+ }
106
142
  workerCollector.register();
107
143
  // ── Register UI + API routes ──────────────────────────
108
144
  await registerHorizonRoutes(storage, {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EACL,aAAa,GAGd,MAAM,YAAY,CAAA;AAKnB,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,8DAA8D;AAE9D,MAAM,OAAO,eAAe;IAClB,MAAM,CAAC,OAAO,GAA0B,IAAI,CAAA;IAEpD,MAAM,CAAC,GAAG,CAAC,OAAuB,IAAU,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA,CAAC,CAAC;IACpE,MAAM,CAAC,GAAG,KAAmC,OAAO,IAAI,CAAC,OAAO,CAAA,CAAC,CAAC;IAClE,mEAAmE;IACnE,MAAM,CAAC,KAAK,KAAiC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAA,CAAC,CAAC;;AAGpE,8DAA8D;AAE9D,MAAM,OAAO,OAAO;IACV,MAAM,CAAC,KAAK;QAClB,MAAM,CAAC,GAAG,eAAe,CAAC,GAAG,EAAE,CAAA;QAC/B,IAAI,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAA;QAChG,OAAO,CAAC,CAAA;IACV,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,OAAwB;QACxC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;IACzC,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,OAAwB;QACxC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;IACzC,CAAC;IAED,MAAM,CAAC,OAAO,CAAC,EAAU;QACvB,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACjC,CAAC;IAED,MAAM,CAAC,cAAc;QACnB,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,cAAc,EAAE,CAAA;IACtC,CAAC;IAED,MAAM,CAAC,OAAO;QACZ,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,CAAA;IAC/B,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,MAAkB;QAChC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACtC,CAAC;CACF;AAED,8DAA8D;AAE9D;;;;;;;;;;GAUG;AACH,MAAM,OAAO,eAAgB,SAAQ,eAAe;IAClD,QAAQ;QACN,IAAI,CAAC,SAAS,CAAC;YACb,IAAI,EAAE,IAAI,GAAG,CAAC,2BAA2B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ;YACpE,EAAE,EAAI,OAAO;YACb,GAAG,EAAG,eAAe;SACtB,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,GAAG,GAAG,MAAM,CAAgB,SAAS,EAAE,EAAE,CAAC,CAAA;QAChD,MAAM,QAAQ,GAAG;YACf,OAAO,EAAY,GAAG,CAAC,OAAO,IAAc,aAAa,CAAC,OAAO;YACjE,IAAI,EAAe,GAAG,CAAC,IAAI,IAAiB,aAAa,CAAC,IAAI;YAC9D,OAAO,EAAY,GAAG,CAAC,OAAO,IAAc,aAAa,CAAC,OAAO;YACjE,UAAU,EAAS,GAAG,CAAC,UAAU,IAAW,aAAa,CAAC,UAAU;YACpE,OAAO,EAAY,GAAG,CAAC,OAAO,IAAc,aAAa,CAAC,OAAO;YACjE,eAAe,EAAI,GAAG,CAAC,eAAe,IAAM,aAAa,CAAC,eAAe;YACzE,iBAAiB,EAAE,GAAG,CAAC,iBAAiB,IAAI,aAAa,CAAC,iBAAiB;YAC3E,IAAI,EAAe,GAAG,CAAC,IAAI,IAAiB,aAAa,CAAC,IAAI;SAC/D,CAAA;QAED,IAAI,CAAC,QAAQ,CAAC,OAAO;YAAE,OAAM;QAE3B,yDAAyD;QACzD,IAAI,OAAuB,CAAA;QAE3B,IAAI,QAAQ,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAClC,OAAO,GAAG,IAAI,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;QAClD,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,IAAI,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QAC/C,CAAC;QAED,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QAC5B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QAErC,yDAAyD;QACzD,MAAM,UAAU,GAAG,QAAQ,CAAC,eAAe,CAAA;QAC3C,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,SAAS,CAAC,CAAA;YACjE,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;gBAC7B,OAAO,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAA;YAC5E,CAAC,EAAE,QAAQ,CAAC,CAAA;YACZ,KAAK,CAAC,KAAK,EAAE,CAAA;QACf,CAAC;QAED,yDAAyD;QACzD,MAAM,YAAY,GAAO,IAAI,YAAY,CAAC,OAAO,CAAC,CAAA;QAClD,MAAM,gBAAgB,GAAG,IAAI,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAA;QAClF,MAAM,eAAe,GAAI,IAAI,eAAe,CAAC,OAAO,CAAC,CAAA;QAErD,YAAY,CAAC,QAAQ,EAAE,CAAA;QACvB,gBAAgB,CAAC,QAAQ,EAAE,CAAA;QAC3B,eAAe,CAAC,QAAQ,EAAE,CAAA;QAE5B,yDAAyD;QACzD,MAAM,qBAAqB,CAAC,OAAO,EAAE;YACnC,IAAI,EAAQ,QAAQ,CAAC,IAAI;YACzB,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClD,CAAC,CAAA;IACJ,CAAC;CACF;AAED,8DAA8D;AAE9D,OAAO,EAAE,qBAAqB,EAAqC,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/routes.js CHANGED
@@ -37,9 +37,9 @@ export async function registerHorizonRoutes(storage, opts = {}) {
37
37
  router.get(`${apiPrefix}/stats`, (req, res) => getStats(storage, req, res), middleware);
38
38
  router.get(`${apiPrefix}/jobs/recent`, (req, res) => listRecentJobs(storage, req, res), middleware);
39
39
  router.get(`${apiPrefix}/jobs/failed`, (req, res) => listFailedJobs(storage, req, res), middleware);
40
- router.get(`${apiPrefix}/jobs/:id`, (req, res) => showJob(storage, req, res), middleware);
41
- router.post(`${apiPrefix}/jobs/:id/retry`, (req, res) => retryJob(storage, req, res), middleware);
42
- router.delete(`${apiPrefix}/jobs/:id`, (req, res) => deleteJob(storage, req, res), middleware);
40
+ router.get(`${apiPrefix}/jobs/:queue/:id`, (req, res) => showJob(storage, req, res), middleware);
41
+ router.post(`${apiPrefix}/jobs/:queue/:id/retry`, (req, res) => retryJob(storage, req, res), middleware);
42
+ router.delete(`${apiPrefix}/jobs/:queue/:id`, (req, res) => deleteJob(storage, req, res), middleware);
43
43
  router.get(`${apiPrefix}/queues`, (req, res) => listQueues(storage, req, res), middleware);
44
44
  router.get(`${apiPrefix}/queues/:queue`, (req, res) => showQueue(storage, req, res), middleware);
45
45
  router.get(`${apiPrefix}/workers`, (req, res) => listWorkers(storage, req, res), middleware);
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
package/dist/storage.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { HorizonStorage, HorizonJob, QueueMetric, WorkerInfo, JobListOptions, JobStatus } from './types.js';
1
+ import type { HorizonStorage, HorizonJob, QueueMetric, WorkerInfo, JobListOptions, JobStatus, HorizonRedisConfig } from './types.js';
2
2
  export declare class MemoryStorage implements HorizonStorage {
3
3
  private readonly maxJobs;
4
4
  private readonly jobs;
@@ -7,16 +7,16 @@ export declare class MemoryStorage implements HorizonStorage {
7
7
  private readonly workerMap;
8
8
  constructor(maxJobs?: number);
9
9
  recordJob(job: HorizonJob): void;
10
- updateJob(id: string, updates: Partial<HorizonJob>): void;
10
+ updateJob(queue: string, id: string, updates: Partial<HorizonJob>): void;
11
11
  recentJobs(options?: JobListOptions): HorizonJob[];
12
12
  failedJobs(options?: JobListOptions): HorizonJob[];
13
- findJob(id: string): HorizonJob | null;
13
+ findJob(queue: string, id: string): HorizonJob | null;
14
14
  recordMetric(metric: QueueMetric): void;
15
15
  metrics(queue: string, since: Date): QueueMetric[];
16
16
  currentMetrics(): QueueMetric[];
17
17
  recordWorker(worker: WorkerInfo): void;
18
18
  workers(): WorkerInfo[];
19
- deleteJob(id: string): void;
19
+ deleteJob(queue: string, id: string): void;
20
20
  pruneOlderThan(date: Date): void;
21
21
  jobCount(status?: JobStatus): number;
22
22
  private filterJobs;
@@ -28,20 +28,60 @@ export declare class SqliteStorage implements HorizonStorage {
28
28
  private getDb;
29
29
  private migrate;
30
30
  recordJob(job: HorizonJob): void;
31
- updateJob(id: string, updates: Partial<HorizonJob>): void;
31
+ updateJob(queue: string, id: string, updates: Partial<HorizonJob>): void;
32
32
  recentJobs(options?: JobListOptions): HorizonJob[];
33
33
  failedJobs(options?: JobListOptions): HorizonJob[];
34
- findJob(id: string): HorizonJob | null;
34
+ findJob(queue: string, id: string): HorizonJob | null;
35
35
  recordMetric(metric: QueueMetric): void;
36
36
  metrics(queue: string, since: Date): QueueMetric[];
37
37
  currentMetrics(): QueueMetric[];
38
38
  recordWorker(worker: WorkerInfo): void;
39
39
  workers(): WorkerInfo[];
40
- deleteJob(id: string): void;
40
+ deleteJob(queue: string, id: string): void;
41
41
  pruneOlderThan(date: Date): void;
42
42
  jobCount(status?: JobStatus): number;
43
43
  private queryJobs;
44
44
  private jobFromRow;
45
45
  private metricFromRow;
46
46
  }
47
+ /**
48
+ * Cross-process job/metric/worker store backed by Redis. Works alongside
49
+ * BullMQ's own Redis instance (separate connection by default) so the dev
50
+ * server and worker process share state.
51
+ *
52
+ * Falls back to memory if `ioredis` cannot be imported — the boot warning
53
+ * surfaces the misconfig.
54
+ */
55
+ export declare class RedisStorage implements HorizonStorage {
56
+ private readonly config;
57
+ private readonly maxJobs;
58
+ private client;
59
+ private readonly prefix;
60
+ constructor(config?: HorizonRedisConfig, maxJobs?: number);
61
+ private getClient;
62
+ private connectionOpts;
63
+ private k;
64
+ private member;
65
+ private parseMember;
66
+ recordJob(job: HorizonJob): Promise<void>;
67
+ updateJob(queue: string, id: string, updates: Partial<HorizonJob>): Promise<void>;
68
+ recentJobs(options?: JobListOptions): Promise<HorizonJob[]>;
69
+ failedJobs(options?: JobListOptions): Promise<HorizonJob[]>;
70
+ findJob(queue: string, id: string): Promise<HorizonJob | null>;
71
+ deleteJob(queue: string, id: string): Promise<void>;
72
+ pruneOlderThan(date: Date): Promise<void>;
73
+ jobCount(status?: JobStatus): Promise<number>;
74
+ recordMetric(metric: QueueMetric): Promise<void>;
75
+ metrics(queue: string, since: Date): Promise<QueueMetric[]>;
76
+ currentMetrics(): Promise<QueueMetric[]>;
77
+ recordWorker(worker: WorkerInfo): Promise<void>;
78
+ workers(): Promise<WorkerInfo[]>;
79
+ /** @internal — close the Redis connection. Used in tests + shutdown. */
80
+ disconnect(): Promise<void>;
81
+ private jobToHash;
82
+ private jobFromHash;
83
+ private metricToHash;
84
+ private metricFromHash;
85
+ private listJobs;
86
+ }
47
87
  //# sourceMappingURL=storage.d.ts.map