velocious 1.0.377 → 1.0.378

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
@@ -1789,7 +1789,8 @@ export default new Configuration({
1789
1789
  host: "127.0.0.1",
1790
1790
  port: 7331,
1791
1791
  databaseIdentifier: "default",
1792
- maxConcurrentInlineJobs: 4
1792
+ maxConcurrentInlineJobs: 4,
1793
+ dispatchStrategy: "beacon"
1793
1794
  }
1794
1795
  })
1795
1796
  ```
@@ -1801,10 +1802,21 @@ VELOCIOUS_BACKGROUND_JOBS_HOST=127.0.0.1
1801
1802
  VELOCIOUS_BACKGROUND_JOBS_PORT=7331
1802
1803
  VELOCIOUS_BACKGROUND_JOBS_DATABASE_IDENTIFIER=default
1803
1804
  VELOCIOUS_BACKGROUND_JOBS_MAX_CONCURRENT_INLINE_JOBS=4
1805
+ VELOCIOUS_BACKGROUND_JOBS_DISPATCH_STRATEGY=beacon
1806
+ VELOCIOUS_BACKGROUND_JOBS_POLL_INTERVAL_MS=1000
1804
1807
  ```
1805
1808
 
1806
1809
  `maxConcurrentInlineJobs` (default: `4`) caps how many `forked: false` jobs a single `background-jobs-worker` process runs in parallel. Concurrency is at the JS event-loop level: every job in flight shares the worker's process and DB connection pool, so the cap should fit the pool, not the CPU count. Forking remains the right tool when you need memory isolation across long-running jobs or want to use more cores.
1807
1810
 
1811
+ ### Dispatch strategy
1812
+
1813
+ `dispatchStrategy` controls how `background-jobs-main` detects new work.
1814
+
1815
+ - `"beacon"` (default): event-driven dispatch. `background-jobs-main` drains the queue when a job is enqueued (directly, or via a [Beacon](docs/beacon.md) broadcast from another process), when a worker comes up or reports ready, and at the exact `scheduled_at_ms` of the next future-scheduled job via a precise `setTimeout`. There is no fixed-interval polling. The `background_jobs` table is the durable log — on (re)connect to Beacon, the dispatcher does a one-shot catch-up drain so anything enqueued while the bus was unreachable is picked up.
1816
+ - `"polling"`: legacy fixed-interval poll. `background-jobs-main` runs `SELECT … FROM background_jobs WHERE status='queued' AND scheduled_at_ms <= now` every `pollIntervalMs` (default `1000`). Use this if you want the previous behavior, or for environments where Beacon is unavailable and you don't want event-driven dispatch.
1817
+
1818
+ Beacon is opt-in for the rest of the framework, but the dispatcher uses event-driven dispatch even when Beacon is not configured — it falls back to direct in-process triggering from the enqueue/handoff paths plus `setTimeout` for scheduled jobs. Configure Beacon when you want cross-process enqueues (e.g. enqueue from an HTTP server process) to wake the main process immediately.
1819
+
1808
1820
  ## Defining jobs
1809
1821
 
1810
1822
  ```js
@@ -13,6 +13,8 @@ export default class BackgroundJobsMain {
13
13
  configuration: import("../configuration.js").default;
14
14
  host: string;
15
15
  port: number;
16
+ dispatchStrategy: import("../configuration-types.js").BackgroundJobsDispatchStrategy;
17
+ pollIntervalMs: number;
16
18
  store: BackgroundJobsStore;
17
19
  logger: Logger;
18
20
  /** @type {Set<JsonSocket>} */
@@ -22,12 +24,24 @@ export default class BackgroundJobsMain {
22
24
  /** @type {net.Server | undefined} */
23
25
  server: net.Server | undefined;
24
26
  /** @type {NodeJS.Timeout | undefined} */
25
- _dispatchTimer: NodeJS.Timeout | undefined;
27
+ _pollTimer: NodeJS.Timeout | undefined;
28
+ /** @type {NodeJS.Timeout | undefined} */
29
+ _scheduledTimer: NodeJS.Timeout | undefined;
30
+ /** @type {NodeJS.Timeout | undefined} */
31
+ _errorRetryTimer: NodeJS.Timeout | undefined;
26
32
  /** @type {NodeJS.Timeout | undefined} */
27
33
  _orphanTimer: NodeJS.Timeout | undefined;
28
34
  /** @type {BackgroundJobsScheduler | undefined} */
29
35
  scheduler: BackgroundJobsScheduler | undefined;
30
- _dispatching: boolean;
36
+ _draining: boolean;
37
+ _redrainQueued: boolean;
38
+ _stopped: boolean;
39
+ /** @type {(() => void) | undefined} */
40
+ _unsubscribeBeacon: (() => void) | undefined;
41
+ /** @type {((...args: any[]) => void) | undefined} */
42
+ _beaconConnectHandler: ((...args: any[]) => void) | undefined;
43
+ /** @type {import("../beacon/client.js").default | import("../beacon/in-process-client.js").default | undefined} */
44
+ _beaconClient: import("../beacon/client.js").default | import("../beacon/in-process-client.js").default | undefined;
31
45
  /**
32
46
  * @returns {Promise<void>} - Resolves when listening.
33
47
  */
@@ -40,6 +54,26 @@ export default class BackgroundJobsMain {
40
54
  * @returns {number} - Bound port.
41
55
  */
42
56
  getPort(): number;
57
+ /**
58
+ * Wires up the dispatch-triggering signal sources for the configured
59
+ * strategy. In `"beacon"` mode (default) this means subscribing to the
60
+ * `velocious-background-jobs-dispatch` channel for cross-process
61
+ * wake-ups, listening for Beacon (re)connects to catch up on missed
62
+ * work, and relying on direct in-process calls from `_handleEnqueue`,
63
+ * `_handleJobComplete`/`Failed`, worker hello/ready, and the
64
+ * scheduled-job `setTimeout`. In `"polling"` mode we restore the
65
+ * legacy fixed-interval poll for users who want the previous behavior.
66
+ * @returns {void}
67
+ */
68
+ _setupDispatchTriggers(): void;
69
+ /**
70
+ * Publishes a dispatch wake-up on the Beacon channel. No-op in polling
71
+ * mode or when Beacon is not connected; in those cases the direct
72
+ * in-process `_drain()` call in the enqueue/handle paths is sufficient
73
+ * (there are no other processes to notify).
74
+ * @returns {void}
75
+ */
76
+ _notifyEnqueued(): void;
43
77
  /**
44
78
  * @param {import("net").Socket} socket - Socket.
45
79
  * @returns {void}
@@ -75,7 +109,46 @@ export default class BackgroundJobsMain {
75
109
  jsonSocket: JsonSocket;
76
110
  message: import("./types.js").BackgroundJobFailedMessage;
77
111
  }): Promise<void>;
78
- _dispatch(): Promise<void>;
112
+ /**
113
+ * Drains all dispatchable jobs to ready workers, then arms the
114
+ * scheduled-job timer for the next future `scheduled_at_ms`. Coalesces
115
+ * concurrent triggers: a wake-up that lands while a drain is in
116
+ * flight just sets a re-drain flag and lets the in-flight drain
117
+ * re-loop after it finishes, so no signal is dropped but no two
118
+ * drains run in parallel.
119
+ *
120
+ * Resilience: in beacon mode this is the sole wake-up path for
121
+ * already-queued work, so a transient DB error during the drain (e.g.
122
+ * `nextAvailableJob()` rejecting) must not strand the queue until the
123
+ * next external signal. On any error we log it and arm a one-shot
124
+ * retry via `_scheduleErrorRetry` using `pollIntervalMs` as the
125
+ * cadence; on success the retry timer is cleared. Polling-mode runs
126
+ * `_drain` from its own interval, so the retry timer is a no-op there.
127
+ * @returns {Promise<void>}
128
+ */
129
+ _drain(): Promise<void>;
130
+ /**
131
+ * Arms a one-shot `setTimeout` to retry `_drain` after a transient
132
+ * failure. Idempotent — repeated calls while a retry is already
133
+ * pending are no-ops. Polling mode already retries via its own
134
+ * interval, so this is a no-op in that mode.
135
+ * @returns {void}
136
+ */
137
+ _scheduleErrorRetry(): void;
138
+ /**
139
+ * Inner drain loop: pulls eligible queued jobs and hands them off to
140
+ * ready workers until one of them runs out.
141
+ * @returns {Promise<void>}
142
+ */
143
+ _drainOnce(): Promise<void>;
144
+ /**
145
+ * Arms a single `setTimeout` for the soonest future-scheduled job's
146
+ * `scheduled_at_ms`. Replaces the second responsibility of the legacy
147
+ * 1-second poll (becoming-eligible scheduled jobs). The timer is
148
+ * idempotently re-armed at the end of every drain.
149
+ * @returns {Promise<void>}
150
+ */
151
+ _armScheduledTimer(): Promise<void>;
79
152
  _sweepOrphans(): Promise<void>;
80
153
  }
81
154
  import BackgroundJobsStore from "./store.js";
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/main.js"],"names":[],"mappings":"AAQA;IACE;;;;;OAKG;IACH,2CAJG;QAAoD,aAAa,EAAzD,OAAO,qBAAqB,EAAE,OAAO;QACvB,IAAI;QACJ,IAAI;KAC5B,EAqBA;IAnBC,qDAAkC;IAElC,aAA+B;IAC/B,aAAyD;IACzD,2BAAoG;IACpG,eAA8B;IAC9B,8BAA8B;IAC9B,SADW,GAAG,CAAC,UAAU,CAAC,CACF;IACxB,8BAA8B;IAC9B,cADW,GAAG,CAAC,UAAU,CAAC,CACG;IAC7B,qCAAqC;IACrC,QADW,GAAG,CAAC,MAAM,GAAG,SAAS,CACV;IACvB,yCAAyC;IACzC,gBADW,MAAM,CAAC,OAAO,GAAG,SAAS,CACN;IAC/B,yCAAyC;IACzC,cADW,MAAM,CAAC,OAAO,GAAG,SAAS,CACR;IAC7B,kDAAkD;IAClD,WADW,uBAAuB,GAAG,SAAS,CACpB;IAC1B,sBAAyB;IAG3B;;OAEG;IACH,SAFa,OAAO,CAAC,IAAI,CAAC,CA6CzB;IAED;;OAEG;IACH,QAFa,OAAO,CAAC,IAAI,CAAC,CAiBzB;IAED;;OAEG;IACH,WAFa,MAAM,CAIlB;IAED;;;OAGG;IACH,0BAHW,OAAO,KAAK,EAAE,MAAM,GAClB,IAAI,CA+DhB;IAED;;;;;OAKG;IACH,wCAJG;QAAyB,UAAU,EAA3B,UAAU;QAC6C,OAAO,EAA9D,OAAO,YAAY,EAAE,2BAA2B;KACxD,GAAU,OAAO,CAAC,IAAI,CAAC,CAgBzB;IAED;;;;;OAKG;IACH,4CAJG;QAAyB,UAAU,EAA3B,UAAU;QAC8C,OAAO,EAA/D,OAAO,YAAY,EAAE,4BAA4B;KACzD,GAAU,OAAO,CAAC,IAAI,CAAC,CAczB;IAED;;;;;OAKG;IACH,0CAJG;QAAyB,UAAU,EAA3B,UAAU;QAC4C,OAAO,EAA7D,OAAO,YAAY,EAAE,0BAA0B;KACvD,GAAU,OAAO,CAAC,IAAI,CAAC,CAgBzB;IAED,2BAyCC;IAED,+BAUC;CACF;gCApS+B,YAAY;mBACzB,cAAc;uBAHV,kBAAkB;gBADzB,KAAK;oCAEe,gBAAgB"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/main.js"],"names":[],"mappings":"AAwBA;IACE;;;;;OAKG;IACH,2CAJG;QAAoD,aAAa,EAAzD,OAAO,qBAAqB,EAAE,OAAO;QACvB,IAAI;QACJ,IAAI;KAC5B,EAmCA;IAjCC,qDAAkC;IAElC,aAA+B;IAC/B,aAAyD;IACzD,qFAA+C;IAC/C,uBAA2C;IAC3C,2BAAoG;IACpG,eAA8B;IAC9B,8BAA8B;IAC9B,SADW,GAAG,CAAC,UAAU,CAAC,CACF;IACxB,8BAA8B;IAC9B,cADW,GAAG,CAAC,UAAU,CAAC,CACG;IAC7B,qCAAqC;IACrC,QADW,GAAG,CAAC,MAAM,GAAG,SAAS,CACV;IACvB,yCAAyC;IACzC,YADW,MAAM,CAAC,OAAO,GAAG,SAAS,CACV;IAC3B,yCAAyC;IACzC,iBADW,MAAM,CAAC,OAAO,GAAG,SAAS,CACL;IAChC,yCAAyC;IACzC,kBADW,MAAM,CAAC,OAAO,GAAG,SAAS,CACJ;IACjC,yCAAyC;IACzC,cADW,MAAM,CAAC,OAAO,GAAG,SAAS,CACR;IAC7B,kDAAkD;IAClD,WADW,uBAAuB,GAAG,SAAS,CACpB;IAC1B,mBAAsB;IACtB,wBAA2B;IAC3B,kBAAqB;IACrB,uCAAuC;IACvC,oBADW,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CACA;IACnC,qDAAqD;IACrD,uBADW,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC,GAAG,SAAS,CACX;IACtC,mHAAmH;IACnH,eADW,OAAO,qBAAqB,EAAE,OAAO,GAAG,OAAO,gCAAgC,EAAE,OAAO,GAAG,SAAS,CACjF;IAGhC;;OAEG;IACH,SAFa,OAAO,CAAC,IAAI,CAAC,CAoDzB;IAED;;OAEG;IACH,QAFa,OAAO,CAAC,IAAI,CAAC,CAqCzB;IAED;;OAEG;IACH,WAFa,MAAM,CAIlB;IAED;;;;;;;;;;OAUG;IACH,0BAFa,IAAI,CA2BhB;IAED;;;;;;OAMG;IACH,mBAFa,IAAI,CAiBhB;IAED;;;OAGG;IACH,0BAHW,OAAO,KAAK,EAAE,MAAM,GAClB,IAAI,CA+DhB;IAED;;;;;OAKG;IACH,wCAJG;QAAyB,UAAU,EAA3B,UAAU;QAC6C,OAAO,EAA9D,OAAO,YAAY,EAAE,2BAA2B;KACxD,GAAU,OAAO,CAAC,IAAI,CAAC,CAiBzB;IAED;;;;;OAKG;IACH,4CAJG;QAAyB,UAAU,EAA3B,UAAU;QAC8C,OAAO,EAA/D,OAAO,YAAY,EAAE,4BAA4B;KACzD,GAAU,OAAO,CAAC,IAAI,CAAC,CAczB;IAED;;;;;OAKG;IACH,0CAJG;QAAyB,UAAU,EAA3B,UAAU;QAC4C,OAAO,EAA7D,OAAO,YAAY,EAAE,0BAA0B;KACvD,GAAU,OAAO,CAAC,IAAI,CAAC,CAmBzB;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,UAFa,OAAO,CAAC,IAAI,CAAC,CA+CzB;IAED;;;;;;OAMG;IACH,uBAFa,IAAI,CAWhB;IAED;;;;OAIG;IACH,cAFa,OAAO,CAAC,IAAI,CAAC,CAkCzB;IAED;;;;;;OAMG;IACH,sBAFa,OAAO,CAAC,IAAI,CAAC,CAoBzB;IAED,+BAcC;CACF;gCA5gB+B,YAAY;mBACzB,cAAc;uBAHV,kBAAkB;gBADzB,KAAK;oCAEe,gBAAgB"}