@teamscala/service-boot 0.23.286 → 0.23.288
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
},
|
|
7
7
|
"name": "@teamscala/service-boot",
|
|
8
8
|
"type": "module",
|
|
9
|
-
"version": "0.23.
|
|
9
|
+
"version": "0.23.288",
|
|
10
10
|
"sideEffects": false,
|
|
11
11
|
"files": [
|
|
12
12
|
"src"
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"@teamscala/auth": "*",
|
|
20
20
|
"@teamscala/aws": "*",
|
|
21
21
|
"@teamscala/cache": "*",
|
|
22
|
+
"@teamscala/channel": "*",
|
|
22
23
|
"@teamscala/chat-completion": "*",
|
|
23
24
|
"@teamscala/db": "*",
|
|
24
25
|
"@teamscala/db-validation": "*",
|
|
@@ -448,6 +449,14 @@
|
|
|
448
449
|
"types": "./src/handlers/bun-stable-watch.d.ts",
|
|
449
450
|
"default": "./src/handlers/bun-stable-watch.ts"
|
|
450
451
|
},
|
|
452
|
+
"./handlers/pane-outbox-drain": {
|
|
453
|
+
"types": "./src/handlers/pane-outbox-drain.d.ts",
|
|
454
|
+
"default": "./src/handlers/pane-outbox-drain.ts"
|
|
455
|
+
},
|
|
456
|
+
"./handlers/pane-outbox-drain.ts": {
|
|
457
|
+
"types": "./src/handlers/pane-outbox-drain.d.ts",
|
|
458
|
+
"default": "./src/handlers/pane-outbox-drain.ts"
|
|
459
|
+
},
|
|
451
460
|
"./handlers/projects-digest": {
|
|
452
461
|
"types": "./src/handlers/projects-digest.d.ts",
|
|
453
462
|
"default": "./src/handlers/projects-digest.ts"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @system server-boot
|
|
3
|
+
* @status handwritten
|
|
4
|
+
* @edit edit directly
|
|
5
|
+
*
|
|
6
|
+
* The `pane-outbox-drain` pg-boss handler — delivers messages the operator's
|
|
7
|
+
* WhatsApp PA queues into `pane_messages` to the addressed agent pane.
|
|
8
|
+
*
|
|
9
|
+
* WHY THE REGISTRATION LIVES HERE AND THE WORK LIVES IN @teamscala/channel.
|
|
10
|
+
* The delivery itself belongs to the channel capability, so `paneOutboxDrainTick`
|
|
11
|
+
* is owned by `@teamscala/channel` beside the dispatch handler it calls. But
|
|
12
|
+
* `pgBossHandlerRegistry` is SERVER tier and `@teamscala/channel` is ADAPTER
|
|
13
|
+
* tier, so the channel package cannot register a pg-boss handler without an
|
|
14
|
+
* upward dependency — forbidden by `vertical-dependency-only`, which has no
|
|
15
|
+
* carve-out. server → adapter is DOWNWARD, so the registration sits here and
|
|
16
|
+
* imports the work, exactly as the four sibling handlers in this directory do.
|
|
17
|
+
*
|
|
18
|
+
* The MountContext route (`ctx.registerScheduledJob`) is tier-legal but NOT
|
|
19
|
+
* usable: `start-scheduled-jobs.ts` offers only `long_running` (invoked once,
|
|
20
|
+
* runs forever) and `recurring` (whose handlers "manage their own setInterval").
|
|
21
|
+
* Both are the in-process timer that `pg-boss-for-background-work` forbids and
|
|
22
|
+
* that the timer half of `in-memory-state-is-not-durable` describes — a timer
|
|
23
|
+
* only fires if its host outlives it, so on a restart-prone service it silently
|
|
24
|
+
* never runs while logging that it started. pg-boss is the only durable option,
|
|
25
|
+
* because the job row outlives any worker.
|
|
26
|
+
*
|
|
27
|
+
* Scoped to scala-channel by its `scheduled_job` row's `service_slug`, so it
|
|
28
|
+
* runs on the service that owns the channel rather than on scala-agents, whose
|
|
29
|
+
* UI-asset build failures used to take PA delivery down with them.
|
|
30
|
+
*
|
|
31
|
+
* Registered under slug `@teamscala/service-boot:pane-outbox-drain`.
|
|
32
|
+
*/
|
|
33
|
+
import { paneOutboxDrainTick } from "@teamscala/channel/pane-outbox/drain-tick";
|
|
34
|
+
import { pgBossHandlerRegistry } from "../pg-boss-handler-registry.ts";
|
|
35
|
+
|
|
36
|
+
pgBossHandlerRegistry.register(
|
|
37
|
+
"@teamscala/service-boot:pane-outbox-drain",
|
|
38
|
+
paneOutboxDrainTick,
|
|
39
|
+
);
|
package/src/pg-boss-mount.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ import "./handlers/upstream-issue-sync.ts";
|
|
|
20
20
|
import "./handlers/scheduled-browser-tests.ts";
|
|
21
21
|
import "./handlers/scala-tools-currency-watch.ts";
|
|
22
22
|
import "./handlers/registry-stale-inactive-sweep.ts";
|
|
23
|
+
import "./handlers/pane-outbox-drain.ts";
|
|
23
24
|
export interface PgBossMountContext {
|
|
24
25
|
databaseUrl: string;
|
|
25
26
|
serviceSlug: string;
|
package/src/pg-boss-mount.ts
CHANGED
|
@@ -33,6 +33,7 @@ import "./handlers/upstream-issue-sync.ts";
|
|
|
33
33
|
import "./handlers/scheduled-browser-tests.ts";
|
|
34
34
|
import "./handlers/scala-tools-currency-watch.ts";
|
|
35
35
|
import "./handlers/registry-stale-inactive-sweep.ts";
|
|
36
|
+
import "./handlers/pane-outbox-drain.ts";
|
|
36
37
|
|
|
37
38
|
export interface PgBossMountContext {
|
|
38
39
|
databaseUrl: string;
|
|
@@ -224,6 +225,28 @@ export async function mountPgBoss(
|
|
|
224
225
|
handlerSlug: config.handler_slug,
|
|
225
226
|
});
|
|
226
227
|
}
|
|
228
|
+
|
|
229
|
+
// A SUCCESSFUL mount emitted nothing until now, while every failure
|
|
230
|
+
// path above recorded an event — so the one state you most need to
|
|
231
|
+
// confirm ("is this job actually scheduled on this service?") was the
|
|
232
|
+
// only one with no evidence. Combined with resolveHandler THROWING
|
|
233
|
+
// into boss.work() rather than warning, that made "never scheduled"
|
|
234
|
+
// and "fired and threw" externally identical, and cost a
|
|
235
|
+
// scheduled_job relocation that had to be reverted undiagnosed on
|
|
236
|
+
// 2026-07-30. Emitting on success makes the mount set queryable
|
|
237
|
+
// (event-log-is-the-only-durable-event-log).
|
|
238
|
+
const mounted = jobs[jobs.length - 1];
|
|
239
|
+
recordEvent({
|
|
240
|
+
kind: "pgboss.job.mounted",
|
|
241
|
+
payload: {
|
|
242
|
+
service: ctx.serviceSlug,
|
|
243
|
+
slug: entry.slug,
|
|
244
|
+
queue: queueName,
|
|
245
|
+
handler: config.handler_slug,
|
|
246
|
+
cron: mounted?.cron ?? null,
|
|
247
|
+
interval_seconds: mounted?.intervalSeconds ?? null,
|
|
248
|
+
},
|
|
249
|
+
});
|
|
227
250
|
} catch (err) {
|
|
228
251
|
// crash-isolation for the mount path: a work()/schedule() failure
|
|
229
252
|
// (e.g. DB not open, queue conflict) degrades to "this job unavailable"
|