@owlmeans/queue 0.1.18-rc.4 → 0.1.18-rc.41

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.
Files changed (110) hide show
  1. package/README.md +286 -8
  2. package/agent-meta/manifest.json +9 -2
  3. package/agent-meta/skills/queue/SKILL.md +243 -12
  4. package/agent-meta/skills/scheduled-jobs/SKILL.md +151 -0
  5. package/build/bridge/types.d.ts +25 -0
  6. package/build/bridge/types.d.ts.map +1 -0
  7. package/build/bridge/types.js +2 -0
  8. package/build/bridge/types.js.map +1 -0
  9. package/build/bridge.d.ts +7 -0
  10. package/build/bridge.d.ts.map +1 -0
  11. package/build/bridge.js +37 -0
  12. package/build/bridge.js.map +1 -0
  13. package/build/config.d.ts +34 -0
  14. package/build/config.d.ts.map +1 -0
  15. package/build/config.js +59 -0
  16. package/build/config.js.map +1 -0
  17. package/build/consts.d.ts +33 -0
  18. package/build/consts.d.ts.map +1 -0
  19. package/build/consts.js +35 -0
  20. package/build/consts.js.map +1 -0
  21. package/build/entrypoint-jobs/types.d.ts +29 -0
  22. package/build/entrypoint-jobs/types.d.ts.map +1 -0
  23. package/build/entrypoint-jobs/types.js +2 -0
  24. package/build/entrypoint-jobs/types.js.map +1 -0
  25. package/build/entrypoint-jobs.d.ts +5 -0
  26. package/build/entrypoint-jobs.d.ts.map +1 -0
  27. package/build/entrypoint-jobs.js +84 -0
  28. package/build/entrypoint-jobs.js.map +1 -0
  29. package/build/errors.d.ts +68 -0
  30. package/build/errors.d.ts.map +1 -0
  31. package/build/errors.js +103 -0
  32. package/build/errors.js.map +1 -0
  33. package/build/index.d.ts +18 -0
  34. package/build/index.d.ts.map +1 -1
  35. package/build/index.js +13 -1
  36. package/build/index.js.map +1 -1
  37. package/build/protocol/types.d.ts +12 -0
  38. package/build/protocol/types.d.ts.map +1 -0
  39. package/build/protocol/types.js +2 -0
  40. package/build/protocol/types.js.map +1 -0
  41. package/build/protocol.d.ts +13 -0
  42. package/build/protocol.d.ts.map +1 -0
  43. package/build/protocol.js +63 -0
  44. package/build/protocol.js.map +1 -0
  45. package/build/queue-config/types.d.ts +29 -0
  46. package/build/queue-config/types.d.ts.map +1 -0
  47. package/build/queue-config/types.js +2 -0
  48. package/build/queue-config/types.js.map +1 -0
  49. package/build/queue-config.d.ts +9 -0
  50. package/build/queue-config.d.ts.map +1 -0
  51. package/build/queue-config.js +83 -0
  52. package/build/queue-config.js.map +1 -0
  53. package/build/queue-route/types.d.ts +14 -0
  54. package/build/queue-route/types.d.ts.map +1 -0
  55. package/build/queue-route/types.js +2 -0
  56. package/build/queue-route/types.js.map +1 -0
  57. package/build/queue-route.d.ts +4 -0
  58. package/build/queue-route.d.ts.map +1 -0
  59. package/build/queue-route.js +24 -0
  60. package/build/queue-route.js.map +1 -0
  61. package/build/route.d.ts +9 -0
  62. package/build/route.d.ts.map +1 -0
  63. package/build/route.js +16 -0
  64. package/build/route.js.map +1 -0
  65. package/build/transport.d.ts +15 -0
  66. package/build/transport.d.ts.map +1 -0
  67. package/build/transport.js +59 -0
  68. package/build/transport.js.map +1 -0
  69. package/build/types.d.ts +312 -0
  70. package/build/types.d.ts.map +1 -0
  71. package/build/types.js +2 -0
  72. package/build/types.js.map +1 -0
  73. package/build/types.local.d.ts +4 -0
  74. package/build/types.local.d.ts.map +1 -0
  75. package/build/types.local.js +2 -0
  76. package/build/types.local.js.map +1 -0
  77. package/build/utils.d.ts +4 -0
  78. package/build/utils.d.ts.map +1 -0
  79. package/build/utils.js +4 -0
  80. package/build/utils.js.map +1 -0
  81. package/build/worker.d.ts +10 -0
  82. package/build/worker.d.ts.map +1 -0
  83. package/build/worker.js +24 -0
  84. package/build/worker.js.map +1 -0
  85. package/package.json +13 -3
  86. package/src/bridge/types.ts +25 -0
  87. package/src/bridge.ts +46 -0
  88. package/src/config.ts +80 -0
  89. package/src/consts.ts +38 -0
  90. package/src/entrypoint-jobs/types.ts +29 -0
  91. package/src/entrypoint-jobs.ts +105 -0
  92. package/src/errors.ts +121 -0
  93. package/src/index.ts +18 -0
  94. package/src/protocol/types.ts +16 -0
  95. package/src/protocol.ts +95 -0
  96. package/src/queue-config/types.ts +29 -0
  97. package/src/queue-config.ts +102 -0
  98. package/src/queue-route/types.ts +14 -0
  99. package/src/queue-route.ts +33 -0
  100. package/src/route.ts +23 -0
  101. package/src/transport.ts +77 -0
  102. package/src/types.ts +326 -0
  103. package/src/utils.ts +5 -0
  104. package/src/worker.ts +27 -0
  105. package/tests/bridge.spec.ts +64 -0
  106. package/tests/config.spec.ts +67 -0
  107. package/tests/protocol.spec.ts +58 -0
  108. package/tests/schedule.spec.ts +99 -0
  109. package/tsconfig.json +1 -0
  110. package/build/.gitkeep +0 -0
@@ -0,0 +1,151 @@
1
+ ---
2
+ name: scheduled-jobs
3
+ description: Recurring background work on OwlMeans queues — declareSchedule in @owlmeans/queue, reconciled into BullMQ job schedulers by @owlmeans/redis-queue when a listening worker starts. Covers interval vs cron schedules, the processor a sweep runs, overlap and restart semantics, renaming and removing a schedule, multi-replica and rolling-deploy behaviour, and testing. Use when adding a nightly or periodic job, replacing a platform CronJob or a setInterval with a schedule, or diagnosing a schedule that does not run.
4
+ user-invocable: false
5
+ ---
6
+ <!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
7
+
8
+ # Scheduled jobs
9
+
10
+ **Layer:** Infra · **Packages:** `@owlmeans/queue` (lead — the declaration), `@owlmeans/redis-queue`
11
+ (the reconciliation)
12
+
13
+ A schedule is a declaration that makes the broker produce an ordinary job on an interval or a cron
14
+ pattern. A worker that consumes the queue runs it with a processor. There is no second scheduler
15
+ process, no cron table and no timer in application code.
16
+
17
+ ## When a schedule is the answer
18
+
19
+ | Situation | Answer |
20
+ |---|---|
21
+ | Periodic sweep, reconciliation, digest, retention delete, rollup | A schedule on a queue a worker consumes |
22
+ | "Remind this user in 20 minutes" | `JobOptions.delay` on one job — a schedule is not per record |
23
+ | A far-future or cancellable per-record deadline | A row with a due date, swept by one schedule |
24
+ | A deployment that runs no worker | A platform `CronJob` calling a guarded entrypoint |
25
+ | A `setInterval` inside a request handler or a long-lived service | A schedule — the interval dies with the process and runs once per replica |
26
+
27
+ Whether the work belongs on a queue at all is `resource-choice`.
28
+
29
+ ## Declaring
30
+
31
+ In the SHARED package every process loads, after the queue:
32
+
33
+ ```typescript
34
+ declareQueue(cfg, APP_MAINTENANCE, ['app:maintenance:reconcile', 'app:maintenance:purge'], {
35
+ worker: { concurrency: 1, lockDuration: 60_000 }
36
+ })
37
+ declareSchedule(cfg, {
38
+ id: 'app-nightly-reconcile', queue: APP_MAINTENANCE, name: 'app:maintenance:reconcile',
39
+ pattern: '17 3 * * *', tz: 'UTC', data: {},
40
+ })
41
+ declareSchedule(cfg, {
42
+ id: 'app-purge-expired', queue: APP_MAINTENANCE, name: 'app:maintenance:purge', every: 15 * 60_000,
43
+ })
44
+ ```
45
+
46
+ And only in the process that runs them: `listenQueues(cfg, APP_MAINTENANCE)` plus a processor per
47
+ job name, registered while the context is wired.
48
+
49
+ - **`pattern` for the calendar, `every` for a frequency.** A nightly job is a pattern with an
50
+ explicit `tz`; "every quarter hour, whenever" is `every`. Pick an odd minute (`17 3 * * *`) so
51
+ many applications' sweeps do not stampede one Redis at the top of the hour.
52
+ - **`every` runs at once** when the scheduler is created (unless `startDate` says otherwise); a
53
+ pattern waits for its next match unless `immediately: true`, which fires only when the scheduler
54
+ is created or its declaration changes — never on an unchanged restart.
55
+ - **The id is permanent.** It is the scheduler's identity in the broker: any other field changes in
56
+ place, a renamed id is a removed schedule plus a new one. Prefix it with the application
57
+ (`app-…`) — ids share one namespace per queue.
58
+ - **Declaration errors surface at boot.** `declareSchedule` throws `UnknownQueue`,
59
+ `UnknownJobName` or `ScheduleMisdeclared` (`<id>:<reason>`) rather than letting the broker fail
60
+ on every tick.
61
+ - **`opts` sets retries and retention for every run; `id` and `delay` are refused** — the broker
62
+ names each run and places it on the schedule.
63
+
64
+ ## Writing the processor
65
+
66
+ ```typescript
67
+ const log = logger('maintenance') // from '@owlmeans/log'
68
+
69
+ worker.process<Record<string, never>, SweepReport>(APP_MAINTENANCE, 'app:maintenance:reconcile',
70
+ async job => {
71
+ const report = { scanned: 0, repaired: 0, failed: 0 }
72
+ for await (const page of organizations({ size: 200 })) {
73
+ await job.touch()
74
+ for (const organization of page) {
75
+ try {
76
+ report.repaired += await reconcile(organization.entityId) ? 1 : 0
77
+ } catch (error) {
78
+ report.failed++
79
+ log.error('Reconcile failed', { entityId: organization.entityId, error })
80
+ }
81
+ report.scanned++
82
+ }
83
+ }
84
+ log.info('Maintenance run finished', { scheduled: job.scheduled, ...report }, { event: 'job.stop' })
85
+ return report
86
+ })
87
+ ```
88
+
89
+ - **A scheduled run has no caller.** No credentials, no entity, no request: it is a processor job,
90
+ never a guarded entrypoint. A step that must go through another service's guard calls that
91
+ service with service credentials.
92
+ - **Idempotent per item, not per run.** A worker rolled out mid-sweep, a stalled lock or a manual
93
+ re-run repeats the whole sweep; each item's repair must be a no-op the second time.
94
+ - **One item's failure is logged and counted, never thrown.** A thrown sweep is retried from the
95
+ start, or dropped after its attempts — either way the other items pay for one bad record.
96
+ - **`touch()` per page.** A sweep over every organization outlives `lockDuration` easily; silence
97
+ hands the job to another worker while this one is still going.
98
+ - **Return a small report.** It lands on the completed job, where an operator reads it.
99
+
100
+ ## Overlap, replicas and deploys
101
+
102
+ - **One job per tick, whatever the replica count.** The broker produces one job; one worker takes
103
+ it. Several replicas listening to the queue do not multiply runs.
104
+ - **Runs can overlap on a concurrent queue.** The next run is produced when the previous one
105
+ starts, so a run that outlasts the interval meets its successor. Put sweeps on their own queue
106
+ with `concurrency: 1`, apart from interactive lanes.
107
+ - **A schedule needs a consumer.** Only a listening worker creates the scheduler, and the next run
108
+ is produced only when the previous one starts processing. A queue nothing consumes stops.
109
+ - **Every listener reconciles at start, from its own configuration.** It creates or updates what it
110
+ declares and removes the schedules it owns (`owlmeans:` scheduler ids) that it does not. Every
111
+ process listening to one queue must load the same schedule list; during a rolling deploy the
112
+ newest process to start wins, and the old pods leave the broker alone after their own start.
113
+ - **Removing a schedule is deleting its declaration.** The next worker start removes the scheduler.
114
+ So is a declaration whose job name the queue no longer accepts, or whose `endDate` has passed.
115
+ - **Scheduling never costs consumption.** A refused declaration or a broker failure while
116
+ reconciling is logged and skipped; the worker keeps consuming. Look for
117
+ `redis-queue-schedules:<queue>` in the worker's log when a schedule does not appear.
118
+
119
+ ## Diagnosing "it never ran"
120
+
121
+ 1. Is some process listening to the queue (`listenQueues`) and is its worker up?
122
+ 2. Did that process's start log a `redis-queue-schedules:<queue>` refusal?
123
+ 3. Does `new Queue(queue, { connection, prefix }).getJobSchedulers()` list `owlmeans:<id>` with the
124
+ expected `pattern`/`every`, `tz` and `next`?
125
+ 4. Is a processor registered for the job name? A run without one fails once as `UnknownJobName`
126
+ and shows in the failed state.
127
+ 5. Is a previous run still active on a `concurrency: 1` queue?
128
+
129
+ ## Testing
130
+
131
+ - **The declaration** is category A in the application's own shared package: build the config,
132
+ `queueConfigOf(cfg).assertSchedules()`, and pin ids and job names against the queue declaration.
133
+ - **The processor** is tested as a function over a fake `JobContext` or a real context — it is
134
+ ordinary code with a `touch`.
135
+ - **Against a broker** (Redis-gated): the worker's Ready-stage start is not awaited by
136
+ `context.init()`, so poll the broker (`getJobSchedulers`) or wait for the first run instead of
137
+ asserting straight after boot. A queue's schedulers go with `obliterate()`.
138
+
139
+ ## External docs
140
+
141
+ - https://docs.bullmq.io/guide/job-schedulers — `upsertJobScheduler(id, { every | pattern, tz,
142
+ startDate, endDate, limit, immediately }, { name, data, opts })` creates or updates one scheduler
143
+ per id and replaces its pending run; `getJobSchedulers()` / `removeJobScheduler(id)`. The next job
144
+ is added when the previous one starts processing, so a worker must be consuming. Produced jobs
145
+ carry `repeatJobKey` = the scheduler id.
146
+
147
+ ## Related
148
+
149
+ - `queue` — `declareSchedule`, `JobContext.scheduled`, processor rules
150
+ - `redis-queue` — `syncSchedules`, the `owlmeans:` ownership prefix, the reconciliation rules
151
+ - `resource-choice` — whether recurring work belongs on a queue at all
@@ -0,0 +1,25 @@
1
+ import type { BasicContext } from '@owlmeans/context';
2
+ import type { AbstractRequest } from '@owlmeans/entrypoint';
3
+ import type { JobEnvelope, QueueJobMeta } from '../types.js';
4
+ /** The envelope ↔ request bridge a queued entrypoint call crosses. */
5
+ export interface QueueBridgeHelper {
6
+ /**
7
+ * Rebuild the request the producer described. A queued call is still a call: the same guards, the
8
+ * same filter, the same handler run against it — only the wire is different.
9
+ */
10
+ requestOf: (envelope: JobEnvelope, path: string, context?: BasicContext<any>, job?: QueueJobMeta) => AbstractRequest;
11
+ /** Read broker identity only where an entrypoint truly needs to bind work to an admission claim. */
12
+ queueJobOf: (request: unknown) => QueueJobMeta | null;
13
+ /**
14
+ * Freshness is judged from when the job was ENQUEUED, not from now.
15
+ *
16
+ * A signed envelope proves who produced it, and a replay window keeps a captured one from being
17
+ * useful forever. But a job can legitimately sit behind a long backlog, and judging it on pickup
18
+ * would reject exactly the work that a busy queue delayed — so the producer's timestamp is what
19
+ * the window applies to.
20
+ *
21
+ * @throws {EnvelopeExpired}
22
+ */
23
+ assertFresh: (envelope: JobEnvelope, ttl?: number) => void;
24
+ }
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/bridge/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE5D,sEAAsE;AACtE,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,SAAS,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,YAAY,KAAK,eAAe,CAAA;IACpH,oGAAoG;IACpG,UAAU,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,YAAY,GAAG,IAAI,CAAA;IACrD;;;;;;;;;OASG;IACH,WAAW,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CAC3D"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/bridge/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ import type { QueueJobMeta } from './types.js';
2
+ import type { QueueBridgeHelper } from './bridge/types.js';
3
+ export declare const createQueueBridgeHelper: () => QueueBridgeHelper;
4
+ export declare const queueBridgeHelper: QueueBridgeHelper;
5
+ /** @deprecated compat:factory-refactor — use `queueBridgeHelper.queueJobOf(…)` */
6
+ export declare const queueJobOf: (request: unknown) => QueueJobMeta | null;
7
+ //# sourceMappingURL=bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,YAAY,EAAE,MAAM,YAAY,CAAA;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAG1D,eAAO,MAAM,uBAAuB,QAAO,iBAkC1C,CAAA;AAED,eAAO,MAAM,iBAAiB,mBAA4B,CAAA;AAE1D,kFAAkF;AAClF,eAAO,MAAM,UAAU,YAAa,OAAO,KAAG,YAAY,GAAG,IAA6C,CAAA"}
@@ -0,0 +1,37 @@
1
+ import { EnvelopeExpired } from './errors.js';
2
+ export const createQueueBridgeHelper = () => {
3
+ const requestOf = (envelope, path, context, job) => ({
4
+ alias: envelope.alias,
5
+ params: (envelope.params ?? {}),
6
+ body: envelope.body,
7
+ headers: (envelope.headers ?? {}),
8
+ query: (envelope.query ?? {}),
9
+ path,
10
+ // Handlers reach their context through `original._ctx`, which the HTTP boundary sets on the raw
11
+ // Fastify request. There is no raw request here, so the shape is supplied deliberately — a
12
+ // handler must not have to know which transport delivered it.
13
+ original: context != null || job != null ? { _ctx: context, _job: job } : undefined,
14
+ });
15
+ const queueJobOf = (request) => {
16
+ if (request == null || typeof request !== 'object' || !('original' in request))
17
+ return null;
18
+ const original = request.original;
19
+ if (original == null || typeof original !== 'object' || !('_job' in original))
20
+ return null;
21
+ return original._job ?? null;
22
+ };
23
+ const assertFresh = (envelope, ttl) => {
24
+ if (ttl == null || envelope.enqueuedAt == null) {
25
+ return;
26
+ }
27
+ const age = (Date.now() - new Date(envelope.enqueuedAt).getTime()) / 1000;
28
+ if (age > ttl) {
29
+ throw new EnvelopeExpired(`${envelope.alias}: ${Math.round(age)}s > ${ttl}s`);
30
+ }
31
+ };
32
+ return { requestOf, queueJobOf, assertFresh };
33
+ };
34
+ export const queueBridgeHelper = createQueueBridgeHelper();
35
+ /** @deprecated compat:factory-refactor — use `queueBridgeHelper.queueJobOf(…)` */
36
+ export const queueJobOf = (request) => queueBridgeHelper.queueJobOf(request);
37
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAsB,EAAE;IAC7D,MAAM,SAAS,GAAG,CAChB,QAAqB,EAAE,IAAY,EAAE,OAA2B,EAAE,GAAkB,EACnE,EAAE,CAAC,CAAC;QACrB,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAA8B;QAC5D,IAAI,EAAE,QAAQ,CAAC,IAA+B;QAC9C,OAAO,EAAE,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAA+B;QAC/D,KAAK,EAAE,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAA6B;QACzD,IAAI;QACJ,gGAAgG;QAChG,2FAA2F;QAC3F,8DAA8D;QAC9D,QAAQ,EAAE,OAAO,IAAI,IAAI,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS;KACpF,CAAC,CAAA;IAEF,MAAM,UAAU,GAAG,CAAC,OAAgB,EAAuB,EAAE;QAC3D,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,UAAU,IAAI,OAAO,CAAC;YAAE,OAAO,IAAI,CAAA;QAC3F,MAAM,QAAQ,GAAI,OAAkC,CAAC,QAAQ,CAAA;QAC7D,IAAI,QAAQ,IAAI,IAAI,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,IAAI,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAA;QAC1F,OAAQ,QAAoC,CAAC,IAAI,IAAI,IAAI,CAAA;IAC3D,CAAC,CAAA;IAED,MAAM,WAAW,GAAG,CAAC,QAAqB,EAAE,GAAY,EAAQ,EAAE;QAChE,IAAI,GAAG,IAAI,IAAI,IAAI,QAAQ,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;YAC/C,OAAM;QACR,CAAC;QACD,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAA;QACzE,IAAI,GAAG,GAAG,GAAG,EAAE,CAAC;YACd,MAAM,IAAI,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,CAAA;QAC/E,CAAC;IACH,CAAC,CAAA;IAED,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,CAAA;AAC/C,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,uBAAuB,EAAE,CAAA;AAE1D,kFAAkF;AAClF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAgB,EAAuB,EAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA"}
@@ -0,0 +1,34 @@
1
+ import type { Config, JobOptions, QueueDeclaration, QueueWorkerOptions, ScheduleDeclaration } from './types.js';
2
+ /**
3
+ * Add a queue to the shared configuration. Every process in the monorepo loads the same
4
+ * declarations — a producer needs them to know a queue exists and what it accepts, a worker needs
5
+ * them to bind. Declaring twice replaces, so a helper that runs per app is safe to call.
6
+ */
7
+ export declare const declareQueue: <C extends Config>(cfg: C, name: string, jobs: string[], opts?: {
8
+ worker?: QueueWorkerOptions;
9
+ defaults?: JobOptions;
10
+ }) => C;
11
+ /**
12
+ * Name the queues this process consumes. It is what turns an otherwise identical binary into a
13
+ * worker, which is why it lives in the process's own config and never in a declaration.
14
+ */
15
+ export declare const listenQueues: <C extends Config>(cfg: C, ...names: string[]) => C;
16
+ /**
17
+ * Add a recurring job to the shared configuration. Declare the queue first — a schedule is checked
18
+ * against it here. Declaring an id twice replaces, like `declareQueue`.
19
+ *
20
+ * Declaring is all this does: the driver creates, updates and removes the broker's schedulers when
21
+ * a worker that listens to the queue starts.
22
+ *
23
+ * @throws {ScheduleMisdeclared} / {UnknownQueue} / {UnknownJobName} — see `assertSchedule`.
24
+ */
25
+ export declare const declareSchedule: <C extends Config>(cfg: C, schedule: ScheduleDeclaration) => C;
26
+ /** @deprecated compat:factory-refactor — use `queueConfigOf(cfg).queueOfJob(…)` */
27
+ export declare const queueOfJob: <C extends Config>(cfg: C, job: string) => QueueDeclaration | undefined;
28
+ /** @deprecated compat:factory-refactor — use `queueConfigOf(cfg).isListening(…)` */
29
+ export declare const isListening: <C extends Config>(cfg: C, name: string) => boolean;
30
+ /** @deprecated compat:factory-refactor — use `queueConfigOf(cfg).schedulesOf(…)` */
31
+ export declare const schedulesOf: <C extends Config>(cfg: C, queue?: string) => ScheduleDeclaration[];
32
+ /** @deprecated compat:factory-refactor — use `queueConfigOf(cfg).assertSchedules()` */
33
+ export declare const assertSchedules: <C extends Config>(cfg: C) => void;
34
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,mBAAmB,EAC9E,MAAM,YAAY,CAAA;AAGnB;;;;GAIG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,OACtC,CAAC,QAAQ,MAAM,QAAQ,MAAM,EAAE,SAAS;IAAE,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAAC,QAAQ,CAAC,EAAE,UAAU,CAAA;CAAE,KAClG,CAcF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,OAAO,CAAC,YAAY,MAAM,EAAE,KAAG,CAM3E,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,MAAM,OAAO,CAAC,YAAY,mBAAmB,KAAG,CAezF,CAAA;AAED,mFAAmF;AACnF,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,MAAM,OAAO,CAAC,OAAO,MAAM,KAAG,gBAAgB,GAAG,SAClD,CAAA;AAEpC,oFAAoF;AACpF,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,OAAO,CAAC,QAAQ,MAAM,KAAG,OAC/B,CAAA;AAEtC,oFAAoF;AACpF,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,OAAO,CAAC,UAAU,MAAM,KAAG,mBAAmB,EACnD,CAAA;AAEvC,uFAAuF;AACvF,eAAO,MAAM,eAAe,GAAI,CAAC,SAAS,MAAM,OAAO,CAAC,KAAG,IAA4C,CAAA"}
@@ -0,0 +1,59 @@
1
+ import { queueConfigOf } from './queue-config.js';
2
+ /**
3
+ * Add a queue to the shared configuration. Every process in the monorepo loads the same
4
+ * declarations — a producer needs them to know a queue exists and what it accepts, a worker needs
5
+ * them to bind. Declaring twice replaces, so a helper that runs per app is safe to call.
6
+ */
7
+ export const declareQueue = (cfg, name, jobs, opts) => {
8
+ const queue = { name, jobs, ...opts };
9
+ const queues = cfg.queue?.queues ?? [];
10
+ const existing = queues.findIndex(declared => declared.name === name);
11
+ if (existing < 0) {
12
+ queues.push(queue);
13
+ }
14
+ else {
15
+ queues[existing] = queue;
16
+ }
17
+ cfg.queue = { ...cfg.queue, queues };
18
+ return cfg;
19
+ };
20
+ /**
21
+ * Name the queues this process consumes. It is what turns an otherwise identical binary into a
22
+ * worker, which is why it lives in the process's own config and never in a declaration.
23
+ */
24
+ export const listenQueues = (cfg, ...names) => {
25
+ const listen = new Set([...(cfg.queue?.listen ?? []), ...names]);
26
+ cfg.queue = { ...cfg.queue, listen: [...listen] };
27
+ return cfg;
28
+ };
29
+ /**
30
+ * Add a recurring job to the shared configuration. Declare the queue first — a schedule is checked
31
+ * against it here. Declaring an id twice replaces, like `declareQueue`.
32
+ *
33
+ * Declaring is all this does: the driver creates, updates and removes the broker's schedulers when
34
+ * a worker that listens to the queue starts.
35
+ *
36
+ * @throws {ScheduleMisdeclared} / {UnknownQueue} / {UnknownJobName} — see `assertSchedule`.
37
+ */
38
+ export const declareSchedule = (cfg, schedule) => {
39
+ queueConfigOf(cfg).assertSchedule(schedule);
40
+ const schedules = cfg.queue?.schedules ?? [];
41
+ const existing = schedules.findIndex(declared => declared.id === schedule.id);
42
+ if (existing < 0) {
43
+ schedules.push(schedule);
44
+ }
45
+ else {
46
+ schedules[existing] = schedule;
47
+ }
48
+ cfg.queue = { ...cfg.queue, schedules };
49
+ return cfg;
50
+ };
51
+ /** @deprecated compat:factory-refactor — use `queueConfigOf(cfg).queueOfJob(…)` */
52
+ export const queueOfJob = (cfg, job) => queueConfigOf(cfg).queueOfJob(job);
53
+ /** @deprecated compat:factory-refactor — use `queueConfigOf(cfg).isListening(…)` */
54
+ export const isListening = (cfg, name) => queueConfigOf(cfg).isListening(name);
55
+ /** @deprecated compat:factory-refactor — use `queueConfigOf(cfg).schedulesOf(…)` */
56
+ export const schedulesOf = (cfg, queue) => queueConfigOf(cfg).schedulesOf(queue);
57
+ /** @deprecated compat:factory-refactor — use `queueConfigOf(cfg).assertSchedules()` */
58
+ export const assertSchedules = (cfg) => queueConfigOf(cfg).assertSchedules();
59
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ export declare const DEFAULT_ALIAS = "queue";
2
+ /**
3
+ * The state a job is in, as the broker reports it. `Waiting` covers both a job queued normally
4
+ * and one held by an unfinished parent — the difference matters to the broker, never to a caller
5
+ * asking whether an answer has arrived.
6
+ */
7
+ export declare enum JobState {
8
+ Waiting = "waiting",
9
+ Delayed = "delayed",
10
+ Active = "active",
11
+ Completed = "completed",
12
+ Failed = "failed",
13
+ Unknown = "unknown"
14
+ }
15
+ export declare enum JobEventType {
16
+ Completed = "completed",
17
+ Failed = "failed",
18
+ Progress = "progress"
19
+ }
20
+ /**
21
+ * How long a caller waits for a reply when neither the route nor the request says. Long enough
22
+ * for work that talks to a model, short enough that a lost job surfaces as an error rather than a
23
+ * hung request.
24
+ */
25
+ export declare const DEFAULT_JOB_TIMEOUT = 60000;
26
+ /**
27
+ * Retries default to one attempt: the jobs here are mostly LLM work, and a blind retry re-spends
28
+ * the tokens that just failed. A queue whose jobs are cheap and idempotent raises it per queue.
29
+ */
30
+ export declare const DEFAULT_ATTEMPTS = 1;
31
+ /** The transport identifier owned by the queue package. */
32
+ export declare const QUEUE_PROTOCOL: 'queue';
33
+ //# sourceMappingURL=consts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa,UAAU,CAAA;AAEpC;;;;GAIG;AACH,oBAAY,QAAQ;IAClB,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,SAAS,cAAc;IACvB,MAAM,WAAW;IACjB,OAAO,YAAY;CACpB;AAED,oBAAY,YAAY;IACtB,SAAS,cAAc;IACvB,MAAM,WAAW;IACjB,QAAQ,aAAa;CACtB;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,QAAS,CAAA;AAEzC;;;GAGG;AACH,eAAO,MAAM,gBAAgB,IAAI,CAAA;AAEjC,2DAA2D;AAC3D,eAAO,MAAM,cAAc,EAAG,OAAgB,CAAA"}
@@ -0,0 +1,35 @@
1
+ export const DEFAULT_ALIAS = 'queue';
2
+ /**
3
+ * The state a job is in, as the broker reports it. `Waiting` covers both a job queued normally
4
+ * and one held by an unfinished parent — the difference matters to the broker, never to a caller
5
+ * asking whether an answer has arrived.
6
+ */
7
+ export var JobState;
8
+ (function (JobState) {
9
+ JobState["Waiting"] = "waiting";
10
+ JobState["Delayed"] = "delayed";
11
+ JobState["Active"] = "active";
12
+ JobState["Completed"] = "completed";
13
+ JobState["Failed"] = "failed";
14
+ JobState["Unknown"] = "unknown";
15
+ })(JobState || (JobState = {}));
16
+ export var JobEventType;
17
+ (function (JobEventType) {
18
+ JobEventType["Completed"] = "completed";
19
+ JobEventType["Failed"] = "failed";
20
+ JobEventType["Progress"] = "progress";
21
+ })(JobEventType || (JobEventType = {}));
22
+ /**
23
+ * How long a caller waits for a reply when neither the route nor the request says. Long enough
24
+ * for work that talks to a model, short enough that a lost job surfaces as an error rather than a
25
+ * hung request.
26
+ */
27
+ export const DEFAULT_JOB_TIMEOUT = 60_000;
28
+ /**
29
+ * Retries default to one attempt: the jobs here are mostly LLM work, and a blind retry re-spends
30
+ * the tokens that just failed. A queue whose jobs are cheap and idempotent raises it per queue.
31
+ */
32
+ export const DEFAULT_ATTEMPTS = 1;
33
+ /** The transport identifier owned by the queue package. */
34
+ export const QUEUE_PROTOCOL = 'queue';
35
+ //# sourceMappingURL=consts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAA;AAEpC;;;;GAIG;AACH,MAAM,CAAN,IAAY,QAOX;AAPD,WAAY,QAAQ;IAClB,+BAAmB,CAAA;IACnB,+BAAmB,CAAA;IACnB,6BAAiB,CAAA;IACjB,mCAAuB,CAAA;IACvB,6BAAiB,CAAA;IACjB,+BAAmB,CAAA;AACrB,CAAC,EAPW,QAAQ,KAAR,QAAQ,QAOnB;AAED,MAAM,CAAN,IAAY,YAIX;AAJD,WAAY,YAAY;IACtB,uCAAuB,CAAA;IACvB,iCAAiB,CAAA;IACjB,qCAAqB,CAAA;AACvB,CAAC,EAJW,YAAY,KAAZ,YAAY,QAIvB;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAA;AAEzC;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAA;AAEjC,2DAA2D;AAC3D,MAAM,CAAC,MAAM,cAAc,GAAG,OAAgB,CAAA"}
@@ -0,0 +1,29 @@
1
+ import type { CommonEntrypoint } from '@owlmeans/entrypoint';
2
+ import type { JobContext, JobEnvelope, JobProcessor, JobReply } from '../types.js';
3
+ /** The queued entrypoints one context serves as a worker, and how a job of theirs is run. */
4
+ export interface EntrypointJobsHelper {
5
+ /**
6
+ * Every queued entrypoint this process both SERVES and LISTENS to, grouped by queue.
7
+ *
8
+ * Both halves are required and they answer different questions. Serving is about code — the alias
9
+ * was bound here, so a handler exists. Listening is about deployment — this process was
10
+ * configured to consume that queue. A worker that bound queues by what it can serve would make
11
+ * every deployment of the same binary a worker for everything it happens to import.
12
+ */
13
+ served: () => Map<string, CommonEntrypoint[]>;
14
+ /**
15
+ * A processor that runs a queued entrypoint call. The driver dispatches by job name, and an
16
+ * entrypoint job's name IS its alias — which is what lets one worker carry both entrypoint jobs
17
+ * and the internal steps an application registers with `process()`.
18
+ */
19
+ processor: () => JobProcessor<JobEnvelope, unknown>;
20
+ /**
21
+ * Run one queued entrypoint call and describe the outcome.
22
+ *
23
+ * It never throws for a DOMAIN failure — the error is marshalled into the returned reply so the
24
+ * producer can rebuild it as its own class, and so the broker does not count a legitimate refusal
25
+ * as a job to retry. Infrastructure failures are left to propagate: those are what retries are for.
26
+ */
27
+ handle: (job: JobContext<JobEnvelope>) => Promise<JobReply>;
28
+ }
29
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/entrypoint-jobs/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAElF,6FAA6F;AAC7F,MAAM,WAAW,oBAAoB;IACnC;;;;;;;OAOG;IACH,MAAM,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAA;IAC7C;;;;OAIG;IACH,SAAS,EAAE,MAAM,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;IACnD;;;;;;OAMG;IACH,MAAM,EAAE,CAAC,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;CAC5D"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/entrypoint-jobs/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import type { Config, Context } from './types.js';
2
+ import type { EntrypointJobsHelper } from './entrypoint-jobs/types.js';
3
+ export declare const makeEntrypointJobsHelper: (context: Context<Config>) => EntrypointJobsHelper;
4
+ export declare const entrypointJobsOf: (target: Context<Config>) => EntrypointJobsHelper;
5
+ //# sourceMappingURL=entrypoint-jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entrypoint-jobs.d.ts","sourceRoot":"","sources":["../src/entrypoint-jobs.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAmD,MAAM,YAAY,CAAA;AAClG,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAMtE,eAAO,MAAM,wBAAwB,YAAa,OAAO,CAAC,MAAM,CAAC,KAAG,oBAyFnE,CAAA;AAED,eAAO,MAAM,gBAAgB,mDAA+C,CAAA"}
@@ -0,0 +1,84 @@
1
+ import { AppType, memoHelper } from '@owlmeans/context';
2
+ import { EntrypointOutcome, provideResponse } from '@owlmeans/entrypoint';
3
+ import { AuthorizationError } from '@owlmeans/auth';
4
+ import { ResilientError } from '@owlmeans/error';
5
+ import { JobNotServed } from './errors.js';
6
+ import { queueBridgeHelper } from './bridge.js';
7
+ import { queueRouteHelper } from './queue-route.js';
8
+ import { makeEntityScope } from '@owlmeans/auth-common';
9
+ export const makeEntrypointJobsHelper = (context) => {
10
+ const served = () => {
11
+ const listen = context.cfg.queue?.listen ?? [];
12
+ const served = new Map();
13
+ context.entrypoints().forEach(entrypoint => {
14
+ const route = entrypoint.route.route;
15
+ if (route.type !== AppType.Backend || !queueRouteHelper.isQueueRoute(route)) {
16
+ return;
17
+ }
18
+ if (route.service != null && route.service !== context.cfg.service) {
19
+ return;
20
+ }
21
+ const { queue } = queueRouteHelper.queueRouteOptions(route);
22
+ if (entrypoint.handle == null || !listen.includes(queue)) {
23
+ return;
24
+ }
25
+ served.set(queue, [...(served.get(queue) ?? []), entrypoint]);
26
+ });
27
+ return served;
28
+ };
29
+ const handle = async (job) => {
30
+ const envelope = job.data;
31
+ try {
32
+ queueBridgeHelper.assertFresh(envelope, context.cfg.queue?.envelopeTtl);
33
+ const entrypoint = context.entrypoint(envelope.alias);
34
+ if (entrypoint.handle == null) {
35
+ throw new JobNotServed(envelope.alias);
36
+ }
37
+ const request = queueBridgeHelper.requestOf(envelope, entrypoint.path(), context, {
38
+ id: job.id, name: job.name, queue: job.queue, attempt: job.attempt, touch: job.touch,
39
+ });
40
+ const response = provideResponse();
41
+ const guards = entrypoint.getGuards();
42
+ if (guards.length > 0) {
43
+ let matched;
44
+ for (const alias of guards) {
45
+ const guard = context.service(alias);
46
+ if (await guard.match(request, response)) {
47
+ matched = guard;
48
+ break;
49
+ }
50
+ }
51
+ if (matched == null) {
52
+ throw new AuthorizationError(`queue:${envelope.alias}`);
53
+ }
54
+ const auth = provideResponse();
55
+ if (!await matched.handle(request, auth)) {
56
+ throw new AuthorizationError(`queue:${envelope.alias}:${matched.alias}`);
57
+ }
58
+ request.auth = auth.value;
59
+ const entity = await makeEntityScope(request).attachEntity(context);
60
+ if (entity != null) {
61
+ request.entity = entity;
62
+ }
63
+ }
64
+ await entrypoint.handle(request, response);
65
+ if (response.error != null) {
66
+ return { error: ResilientError.marshal(response.error).message };
67
+ }
68
+ return { value: response.value, outcome: response.outcome ?? EntrypointOutcome.Ok };
69
+ }
70
+ catch (e) {
71
+ // A refusal the caller must see as its own class — `ContentRefused`, `AgentLocked` — travels
72
+ // in the reply. Only a broker- or connection-level fault should ever reach the retry logic:
73
+ // retrying a refusal just spends the work again to be refused identically.
74
+ if (e instanceof ResilientError) {
75
+ return { error: ResilientError.marshal(e).message };
76
+ }
77
+ throw e;
78
+ }
79
+ };
80
+ const processor = () => async (job) => await handle(job);
81
+ return { served, processor, handle };
82
+ };
83
+ export const entrypointJobsOf = memoHelper.oncePer(makeEntrypointJobsHelper);
84
+ //# sourceMappingURL=entrypoint-jobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entrypoint-jobs.js","sourceRoot":"","sources":["../src/entrypoint-jobs.ts"],"names":[],"mappings":"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"}