@owlmeans/queue 0.1.18-rc.23 → 0.1.18-rc.25
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 +7 -6
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/queue/SKILL.md +10 -6
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/protocol.d.ts.map +1 -1
- package/build/protocol.js +4 -7
- package/build/protocol.js.map +1 -1
- package/build/route.d.ts +15 -0
- package/build/route.d.ts.map +1 -0
- package/build/route.js +32 -0
- package/build/route.js.map +1 -0
- package/build/transport.d.ts.map +1 -1
- package/build/transport.js +8 -11
- package/build/transport.js.map +1 -1
- package/build/worker.d.ts.map +1 -1
- package/build/worker.js +5 -4
- package/build/worker.js.map +1 -1
- package/package.json +8 -8
- package/src/index.ts +1 -0
- package/src/protocol.ts +4 -7
- package/src/route.ts +48 -0
- package/src/transport.ts +8 -11
- package/src/worker.ts +5 -4
- package/tests/protocol.spec.ts +2 -2
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ and on the driver only where the application wires itself up.
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
bun add @owlmeans/queue@^0.1.18-rc.
|
|
19
|
+
bun add @owlmeans/queue@^0.1.18-rc.25
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
## Concepts
|
|
@@ -26,8 +26,8 @@ bun add @owlmeans/queue@^0.1.18-rc.23
|
|
|
26
26
|
address, not a deployment.
|
|
27
27
|
- **Listen**: `listenQueues(cfg, ...names)` in one process's own config says which queues *that
|
|
28
28
|
process* consumes. A process that listens to nothing is a producer only.
|
|
29
|
-
- **Queued protocol**: an immutable entrypoint protocol whose route uses `job()`
|
|
30
|
-
|
|
29
|
+
- **Queued protocol**: an immutable backend entrypoint protocol whose route uses `job()` from this
|
|
30
|
+
package (`QUEUE_PROTOCOL`). Callers use `ctx.entrypoint(protocol).call(...)` unchanged,
|
|
31
31
|
and the QUEUE transport carries the call through the broker.
|
|
32
32
|
- **Job record**: `ctx.jobs(queue)` returns a `QueueResource`, the ordinary `Resource<JobRecord>`
|
|
33
33
|
contract plus `wait`, `flow`, `counts` and `close`. `create` enqueues, `list` inspects and `take`
|
|
@@ -80,7 +80,8 @@ appendRedisQueue(context, { hooks: billingQueueHooks(context) })
|
|
|
80
80
|
|
|
81
81
|
```ts
|
|
82
82
|
import { contract, protocol, typed } from '@owlmeans/entrypoint'
|
|
83
|
-
import {
|
|
83
|
+
import { job } from '@owlmeans/queue'
|
|
84
|
+
import { backend, route } from '@owlmeans/route'
|
|
84
85
|
|
|
85
86
|
const aliases = { base: 'app:report', build: 'app:report:build' } as const
|
|
86
87
|
const reportBase = protocol(route(aliases.base, '/reports', backend({ service: APP_WORKER })), contract())
|
|
@@ -286,7 +287,7 @@ not the job, so read the job back to learn what became of it.
|
|
|
286
287
|
## Related packages
|
|
287
288
|
|
|
288
289
|
- [`@owlmeans/redis-queue`](../redis-queue): the BullMQ driver, and where queue integration tests live
|
|
289
|
-
- [`@owlmeans/route`](../route):
|
|
290
|
+
- [`@owlmeans/route`](../route): transport-neutral route declarations used by the queue-owned `job()` builder
|
|
290
291
|
- [`@owlmeans/entrypoint`](../entrypoint): protocol declarations and the transport seam
|
|
291
292
|
- [`@owlmeans/resource`](../resource): the `Resource` contract jobs are read through
|
|
292
293
|
- [`@owlmeans/server-job`](../server-job) / [`@owlmeans/client-job`](../client-job): listing,
|
|
@@ -300,7 +301,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
300
301
|
your project's skill store (`.agents/skills/`):
|
|
301
302
|
|
|
302
303
|
```sh
|
|
303
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
304
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.31
|
|
304
305
|
```
|
|
305
306
|
|
|
306
307
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/queue",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-09-
|
|
4
|
+
"version": "0.1.18-rc.25",
|
|
5
|
+
"generatedAt": "2026-09-21T21:54:22.945Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -8,19 +8,20 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/queue
|
|
9
9
|
|
|
10
10
|
**Layer:** Infra
|
|
11
|
-
**Install:** `"@owlmeans/queue": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/queue": "^0.1.18-rc.25"` in `dependencies`
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
them. Depend on this one from a shared
|
|
13
|
+
Backend transport contracts only. It carries no broker code — a driver package
|
|
14
|
+
(`@owlmeans/redis-queue`) implements them. Depend on this one from a shared backend package;
|
|
15
|
+
generic common and frontend packages must not import it. Depend on the driver only where the
|
|
15
16
|
application wires itself up.
|
|
16
17
|
|
|
17
18
|
## The one idea
|
|
18
19
|
|
|
19
|
-
A queued call is an immutable entrypoint protocol whose route names `
|
|
20
|
+
A queued call is an immutable entrypoint protocol whose route names `QUEUE_PROTOCOL`.
|
|
20
21
|
Ordinary calls use `ctx.entrypoint(protocol).call(request)`. Code that needs broker options or a
|
|
21
22
|
job handle uses `enqueueProtocol(ctx, protocol, request, options)` and
|
|
22
23
|
`waitForProtocol(ctx, protocol, job)`. Both derive queue and job name from the protocol object and
|
|
23
|
-
preserve its exact request/reply pair; raw strings and non-
|
|
24
|
+
preserve its exact request/reply pair; raw strings and non-queue declarations are rejected.
|
|
24
25
|
|
|
25
26
|
That is what makes it worth having: moving a service-to-service call onto the broker is a change
|
|
26
27
|
to a declaration, not to the places that call it, and the broker holds the work across a restart of
|
|
@@ -60,6 +61,9 @@ protocol(
|
|
|
60
61
|
)
|
|
61
62
|
```
|
|
62
63
|
|
|
64
|
+
Import `job`, `QUEUE_PROTOCOL`, `isQueueRoute` and `queueRouteOptions` from `@owlmeans/queue`.
|
|
65
|
+
The generic route package deliberately knows none of the queue option shape.
|
|
66
|
+
|
|
63
67
|
The alias appears in `declareQueue(...jobs)` only because the broker is a string-keyed adapter.
|
|
64
68
|
Application producers and handlers keep the protocol object.
|
|
65
69
|
|
|
@@ -241,7 +245,7 @@ listens to, grouped by queue, which is what a driver binds.
|
|
|
241
245
|
|
|
242
246
|
- `@owlmeans/context` — service registration and the middleware stage
|
|
243
247
|
- `@owlmeans/entrypoint` — the transport seam and the served-entrypoint dispatch
|
|
244
|
-
- `@owlmeans/route` — `
|
|
248
|
+
- `@owlmeans/route` — the generic declaration model that `QUEUE_PROTOCOL` and `job()` extend
|
|
245
249
|
- `@owlmeans/resource` — the `Resource` contract jobs are read through
|
|
246
250
|
- `@owlmeans/auth` / `@owlmeans/auth-common` — guarding a queued call and attaching its entity
|
|
247
251
|
- `@owlmeans/error` — marshalling a refusal across the hop
|
package/build/index.d.ts
CHANGED
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA"}
|
package/build/index.js
CHANGED
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA"}
|
package/build/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAMhG,OAAO,KAAK,EACV,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAC3E,MAAM,YAAY,CAAA;AAEnB,KAAK,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,6BAA6B,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAMhG,OAAO,KAAK,EACV,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAC3E,MAAM,YAAY,CAAA;AAEnB,KAAK,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,WAAW,CAAA;AAoBjD,iGAAiG;AACjG,eAAO,MAAM,eAAe,GAAU,QAAQ,SAAS,6BAA6B,WACzE,YAAY,eACR,QAAQ,WACZ,SAAS,CAAC,QAAQ,CAAC,YAClB,UAAU,KACnB,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAkBhE,CAAA;AAED,qEAAqE;AACrE,eAAO,MAAM,eAAe,GAAU,QAAQ,SAAS,6BAA6B,WACzE,YAAY,eACR,QAAQ,OAChB,MAAM,GAAG,SAAS,CAAC,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,YAC1D;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,KAC7B,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAe9B,CAAA"}
|
package/build/protocol.js
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
import { isEntrypointProtocol } from '@owlmeans/entrypoint';
|
|
2
2
|
import { ResilientError } from '@owlmeans/error';
|
|
3
|
-
import { RouteProtocols } from '@owlmeans/route';
|
|
4
3
|
import { queueOf } from './config.js';
|
|
5
4
|
import { UnknownQueue } from './errors.js';
|
|
5
|
+
import { isQueueRoute, queueRouteOptions } from './route.js';
|
|
6
6
|
const queueFor = (context, declaration) => {
|
|
7
7
|
if (declaration == null || typeof declaration !== 'object' || !isEntrypointProtocol(declaration)) {
|
|
8
8
|
throw new UnknownQueue('protocol declaration required');
|
|
9
9
|
}
|
|
10
|
-
if (declaration.route
|
|
11
|
-
throw new UnknownQueue(`${declaration.alias}: not a
|
|
12
|
-
}
|
|
13
|
-
const queue = declaration.route.route.queue;
|
|
14
|
-
if (queue == null) {
|
|
15
|
-
throw new UnknownQueue(`${declaration.alias}: route declares no queue`);
|
|
10
|
+
if (!isQueueRoute(declaration.route)) {
|
|
11
|
+
throw new UnknownQueue(`${declaration.alias}: not a queue protocol`);
|
|
16
12
|
}
|
|
13
|
+
const { queue } = queueRouteOptions(declaration.route);
|
|
17
14
|
const configured = queueOf(context.cfg, queue);
|
|
18
15
|
if (!configured.jobs.includes(declaration.alias)) {
|
|
19
16
|
throw new UnknownQueue(`${queue}:${declaration.alias}`);
|
package/build/protocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
|
package/build/route.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RouteDeclaration, RouteModel, RouteOptions } from '@owlmeans/route';
|
|
2
|
+
/** The transport identifier owned by the queue package. */
|
|
3
|
+
export declare const QUEUE_PROTOCOL: 'queue';
|
|
4
|
+
/** Queue-owned options stored in a generic route declaration. */
|
|
5
|
+
export interface QueueRouteOptions extends Omit<RouteOptions, 'protocol' | 'protocolOptions'> {
|
|
6
|
+
queue: string;
|
|
7
|
+
reply?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/** Declare a backend route carried by a queue. */
|
|
10
|
+
export declare const job: (opts: QueueRouteOptions, secondary?: Omit<QueueRouteOptions, 'queue'>) => Partial<RouteOptions>;
|
|
11
|
+
/** Whether a declaration belongs to the queue transport. */
|
|
12
|
+
export declare const isQueueRoute: (route: RouteDeclaration | RouteModel) => boolean;
|
|
13
|
+
/** Read and validate queue-owned route options. */
|
|
14
|
+
export declare const queueRouteOptions: (route: RouteDeclaration | RouteModel) => Pick<QueueRouteOptions, 'queue' | 'reply'>;
|
|
15
|
+
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAGjF,2DAA2D;AAC3D,eAAO,MAAM,cAAc,EAAG,OAAgB,CAAA;AAE9C,iEAAiE;AACjE,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,YAAY,EAAE,UAAU,GAAG,iBAAiB,CAAC;IAC3F,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,kDAAkD;AAClD,eAAO,MAAM,GAAG,SACR,iBAAiB,cACX,IAAI,CAAC,iBAAiB,EAAE,OAAO,CAAC,KAC3C,OAAO,CAAC,YAAY,CAMtB,CAAA;AAED,4DAA4D;AAC5D,eAAO,MAAM,YAAY,UAAW,gBAAgB,GAAG,UAAU,KAAG,OACE,CAAA;AAEtE,mDAAmD;AACnD,eAAO,MAAM,iBAAiB,UACrB,gBAAgB,GAAG,UAAU,KACnC,IAAI,CAAC,iBAAiB,EAAE,OAAO,GAAG,OAAO,CAe3C,CAAA"}
|
package/build/route.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { backend } from '@owlmeans/route';
|
|
2
|
+
import { UnknownQueue } from './errors.js';
|
|
3
|
+
/** The transport identifier owned by the queue package. */
|
|
4
|
+
export const QUEUE_PROTOCOL = 'queue';
|
|
5
|
+
/** Declare a backend route carried by a queue. */
|
|
6
|
+
export const job = (opts, secondary) => {
|
|
7
|
+
const { queue, reply, ...routeOptions } = { ...opts, ...secondary };
|
|
8
|
+
const declaration = backend(routeOptions);
|
|
9
|
+
declaration.protocol = QUEUE_PROTOCOL;
|
|
10
|
+
declaration.protocolOptions = { queue, ...(reply == null ? {} : { reply }) };
|
|
11
|
+
return declaration;
|
|
12
|
+
};
|
|
13
|
+
/** Whether a declaration belongs to the queue transport. */
|
|
14
|
+
export const isQueueRoute = (route) => ('route' in route ? route.route : route).protocol === QUEUE_PROTOCOL;
|
|
15
|
+
/** Read and validate queue-owned route options. */
|
|
16
|
+
export const queueRouteOptions = (route) => {
|
|
17
|
+
const declaration = 'route' in route ? route.route : route;
|
|
18
|
+
if (declaration.protocol !== QUEUE_PROTOCOL
|
|
19
|
+
|| declaration.protocolOptions == null
|
|
20
|
+
|| typeof declaration.protocolOptions !== 'object') {
|
|
21
|
+
throw new UnknownQueue(`${declaration.alias}: not a queue protocol`);
|
|
22
|
+
}
|
|
23
|
+
const options = declaration.protocolOptions;
|
|
24
|
+
if (typeof options.queue !== 'string' || options.queue.trim() === '') {
|
|
25
|
+
throw new UnknownQueue(`${declaration.alias}: route declares no queue`);
|
|
26
|
+
}
|
|
27
|
+
if (options.reply != null && typeof options.reply !== 'boolean') {
|
|
28
|
+
throw new UnknownQueue(`${declaration.alias}: invalid queue reply option`);
|
|
29
|
+
}
|
|
30
|
+
return { queue: options.queue, reply: options.reply };
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,2DAA2D;AAC3D,MAAM,CAAC,MAAM,cAAc,GAAG,OAAgB,CAAA;AAQ9C,kDAAkD;AAClD,MAAM,CAAC,MAAM,GAAG,GAAG,CACjB,IAAuB,EACvB,SAA4C,EACrB,EAAE;IACzB,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,SAAS,EAAE,CAAA;IACnE,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACzC,WAAW,CAAC,QAAQ,GAAG,cAAc,CAAA;IACrC,WAAW,CAAC,eAAe,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAA;IAC5E,OAAO,WAAW,CAAA;AACpB,CAAC,CAAA;AAED,4DAA4D;AAC5D,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAoC,EAAW,EAAE,CAC5E,CAAC,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,KAAK,cAAc,CAAA;AAEtE,mDAAmD;AACnD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,KAAoC,EACQ,EAAE;IAC9C,MAAM,WAAW,GAAG,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAA;IAC1D,IAAI,WAAW,CAAC,QAAQ,KAAK,cAAc;WACtC,WAAW,CAAC,eAAe,IAAI,IAAI;WACnC,OAAO,WAAW,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;QACrD,MAAM,IAAI,YAAY,CAAC,GAAG,WAAW,CAAC,KAAK,wBAAwB,CAAC,CAAA;IACtE,CAAC;IACD,MAAM,OAAO,GAAG,WAAW,CAAC,eAA0C,CAAA;IACtE,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACrE,MAAM,IAAI,YAAY,CAAC,GAAG,WAAW,CAAC,KAAK,2BAA2B,CAAC,CAAA;IACzE,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,IAAI,IAAI,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAChE,MAAM,IAAI,YAAY,CAAC,GAAG,WAAW,CAAC,KAAK,8BAA8B,CAAC,CAAA;IAC5E,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAA4B,EAAE,CAAA;AAC9E,CAAC,CAAA"}
|
package/build/transport.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAqC,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAqC,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAIlG,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAsC,MAAM,YAAY,CAAA;AAIrF;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,WAAW,MAAM,wBAiD/C,CAAA;AAED,eAAO,MAAM,oBAAoB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,WAC7E,CAAC,UAAU,MAAM,KACzB,CAMF,CAAA"}
|
package/build/transport.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { assertContext, createService } from '@owlmeans/context';
|
|
2
2
|
import { EntrypointOutcome, transportAlias } from '@owlmeans/entrypoint';
|
|
3
|
-
import { RouteProtocols } from '@owlmeans/route';
|
|
4
3
|
import { ResilientError } from '@owlmeans/error';
|
|
5
4
|
import { DEFAULT_JOB_TIMEOUT } from './consts.js';
|
|
6
|
-
import {
|
|
5
|
+
import { QUEUE_PROTOCOL, queueRouteOptions } from './route.js';
|
|
7
6
|
/**
|
|
8
7
|
* The producing half of the bridge: it turns a call on a QUEUE entrypoint into a job, and the
|
|
9
8
|
* job's outcome back into a reply.
|
|
@@ -14,18 +13,16 @@ import { UnknownQueue } from './errors.js';
|
|
|
14
13
|
* the request rather than from the entrypoint: the far side rebuilds a request, and anything only
|
|
15
14
|
* HTTP understands would not survive the trip anyway.
|
|
16
15
|
*/
|
|
17
|
-
export const makeQueueTransport = (alias = transportAlias(
|
|
16
|
+
export const makeQueueTransport = (alias = transportAlias(QUEUE_PROTOCOL)) => {
|
|
18
17
|
const location = `queue-transport:${alias}`;
|
|
19
18
|
const service = createService(alias, {
|
|
20
|
-
protocol:
|
|
19
|
+
protocol: QUEUE_PROTOCOL,
|
|
21
20
|
handle: (async (req, res) => {
|
|
22
21
|
const context = assertContext(service.ctx, location);
|
|
23
22
|
const entrypoint = context.entrypoint(req.alias);
|
|
24
23
|
const route = entrypoint.route.route;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
const jobs = context.jobs(route.queue);
|
|
24
|
+
const { queue, reply: waitsForReply } = queueRouteOptions(route);
|
|
25
|
+
const jobs = context.jobs(queue);
|
|
29
26
|
const envelope = {
|
|
30
27
|
alias: req.alias,
|
|
31
28
|
params: req.params,
|
|
@@ -34,11 +31,11 @@ export const makeQueueTransport = (alias = transportAlias(RouteProtocols.QUEUE))
|
|
|
34
31
|
headers: req.headers,
|
|
35
32
|
enqueuedAt: new Date().toISOString(),
|
|
36
33
|
};
|
|
37
|
-
const job = await jobs.create({ queue
|
|
34
|
+
const job = await jobs.create({ queue, name: req.alias, data: envelope });
|
|
38
35
|
// `reply: false` says the caller is not waiting for the work, only for the promise that it
|
|
39
36
|
// was taken. `Accepted` plus the job's identity is the whole answer — enough to watch it.
|
|
40
|
-
if (
|
|
41
|
-
res.resolve({ id: job.id, queue
|
|
37
|
+
if (waitsForReply === false) {
|
|
38
|
+
res.resolve({ id: job.id, queue }, EntrypointOutcome.Accepted);
|
|
42
39
|
return;
|
|
43
40
|
}
|
|
44
41
|
const reply = await jobs.wait(job.id, {
|
package/build/transport.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEhE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
|
package/build/worker.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAEnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAEnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAc,WAAW,EAAE,YAAY,EAAsB,MAAM,YAAY,CAAA;AAK5G;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,WACtD,CAAC,KACT,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAqBhC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,WAC/D,CAAC,KACT,YAAY,CAAC,WAAW,EAAE,OAAO,CACmC,CAAA;AAEvE;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,WAAW,MAAM,KAAmB,UAcpE,CAAA"}
|
package/build/worker.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MiddlewareStage, MiddlewareType, AppType } from '@owlmeans/context';
|
|
2
|
-
import { RouteProtocols } from '@owlmeans/route';
|
|
3
2
|
import { handleJob } from './bridge.js';
|
|
4
3
|
import { DEFAULT_ALIAS } from './consts.js';
|
|
4
|
+
import { isQueueRoute, queueRouteOptions } from './route.js';
|
|
5
5
|
/**
|
|
6
6
|
* Every queued entrypoint this process both SERVES and LISTENS to, grouped by queue.
|
|
7
7
|
*
|
|
@@ -15,16 +15,17 @@ export const servedJobs = (context) => {
|
|
|
15
15
|
const served = new Map();
|
|
16
16
|
context.entrypoints().forEach(entrypoint => {
|
|
17
17
|
const route = entrypoint.route.route;
|
|
18
|
-
if (route.type !== AppType.Backend || route
|
|
18
|
+
if (route.type !== AppType.Backend || !isQueueRoute(route)) {
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
if (route.service != null && route.service !== context.cfg.service) {
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
const { queue } = queueRouteOptions(route);
|
|
25
|
+
if (entrypoint.handle == null || !listen.includes(queue)) {
|
|
25
26
|
return;
|
|
26
27
|
}
|
|
27
|
-
served.set(
|
|
28
|
+
served.set(queue, [...(served.get(queue) ?? []), entrypoint]);
|
|
28
29
|
});
|
|
29
30
|
return served;
|
|
30
31
|
};
|
package/build/worker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAG5E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAE5D;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,OAAU,EACuB,EAAE;IACnC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,CAAA;IAC9C,MAAM,MAAM,GAAG,IAAI,GAAG,EAA8B,CAAA;IAEpD,OAAO,CAAC,WAAW,EAAoB,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;QAC3D,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAA;QACpC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3D,OAAM;QACR,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,IAAI,IAAI,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACnE,OAAM;QACR,CAAC;QACD,MAAM,EAAE,KAAK,EAAE,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAA;QAC1C,IAAI,UAAU,CAAC,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACzD,OAAM;QACR,CAAC;QAED,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC,CAAA;IAC/D,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,OAAU,EAC0B,EAAE,CACtC,KAAK,EAAE,GAA4B,EAAE,EAAE,CAAC,MAAM,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;AAEvE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAK,GAAW,aAAa,EAAc,EAAE,CAAC,CAAC;IACnF,IAAI,EAAE,cAAc,CAAC,OAAO;IAC5B,KAAK,EAAE,eAAe,CAAC,KAAK;IAC5B,KAAK,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;QACrB,MAAM,GAAG,GAAG,OAAqC,CAAA;QACjD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/C,OAAM;QACR,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAM;QACR,CAAC;QAED,MAAM,GAAG,CAAC,OAAO,CAAqB,KAAK,CAAC,CAAC,KAAK,EAAE,CAAA;IACtD,CAAC;CACF,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/queue",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.25",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"access": "public"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@owlmeans/auth": "^0.1.18-rc.
|
|
35
|
-
"@owlmeans/auth-common": "^0.1.18-rc.
|
|
36
|
-
"@owlmeans/context": "^0.1.18-rc.
|
|
37
|
-
"@owlmeans/entrypoint": "^0.1.18-rc.
|
|
38
|
-
"@owlmeans/error": "^0.1.18-rc.
|
|
39
|
-
"@owlmeans/resource": "^0.1.18-rc.
|
|
40
|
-
"@owlmeans/route": "^0.1.18-rc.
|
|
34
|
+
"@owlmeans/auth": "^0.1.18-rc.29",
|
|
35
|
+
"@owlmeans/auth-common": "^0.1.18-rc.31",
|
|
36
|
+
"@owlmeans/context": "^0.1.18-rc.27",
|
|
37
|
+
"@owlmeans/entrypoint": "^0.1.18-rc.30",
|
|
38
|
+
"@owlmeans/error": "^0.1.18-rc.29",
|
|
39
|
+
"@owlmeans/resource": "^0.1.18-rc.29",
|
|
40
|
+
"@owlmeans/route": "^0.1.18-rc.28"
|
|
41
41
|
}
|
|
42
42
|
}
|
package/src/index.ts
CHANGED
package/src/protocol.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { EntrypointProtocolDeclaration, RequestOf, ResponseOf } from '@owlmeans/entrypoint'
|
|
2
2
|
import { isEntrypointProtocol } from '@owlmeans/entrypoint'
|
|
3
3
|
import { ResilientError } from '@owlmeans/error'
|
|
4
|
-
import { RouteProtocols } from '@owlmeans/route'
|
|
5
4
|
import { queueOf } from './config.js'
|
|
6
5
|
import { UnknownQueue } from './errors.js'
|
|
6
|
+
import { isQueueRoute, queueRouteOptions } from './route.js'
|
|
7
7
|
import type {
|
|
8
8
|
Config, Context, JobEnvelope, JobOptions, JobRecord, JobReply, QueueAppend,
|
|
9
9
|
} from './types.js'
|
|
@@ -17,13 +17,10 @@ const queueFor = (context: QueueContext, declaration: unknown): {
|
|
|
17
17
|
if (declaration == null || typeof declaration !== 'object' || !isEntrypointProtocol(declaration)) {
|
|
18
18
|
throw new UnknownQueue('protocol declaration required')
|
|
19
19
|
}
|
|
20
|
-
if (declaration.route
|
|
21
|
-
throw new UnknownQueue(`${declaration.alias}: not a
|
|
22
|
-
}
|
|
23
|
-
const queue = declaration.route.route.queue
|
|
24
|
-
if (queue == null) {
|
|
25
|
-
throw new UnknownQueue(`${declaration.alias}: route declares no queue`)
|
|
20
|
+
if (!isQueueRoute(declaration.route)) {
|
|
21
|
+
throw new UnknownQueue(`${declaration.alias}: not a queue protocol`)
|
|
26
22
|
}
|
|
23
|
+
const { queue } = queueRouteOptions(declaration.route)
|
|
27
24
|
const configured = queueOf(context.cfg, queue)
|
|
28
25
|
if (!configured.jobs.includes(declaration.alias)) {
|
|
29
26
|
throw new UnknownQueue(`${queue}:${declaration.alias}`)
|
package/src/route.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { backend } from '@owlmeans/route'
|
|
2
|
+
import type { RouteDeclaration, RouteModel, RouteOptions } from '@owlmeans/route'
|
|
3
|
+
import { UnknownQueue } from './errors.js'
|
|
4
|
+
|
|
5
|
+
/** The transport identifier owned by the queue package. */
|
|
6
|
+
export const QUEUE_PROTOCOL = 'queue' as const
|
|
7
|
+
|
|
8
|
+
/** Queue-owned options stored in a generic route declaration. */
|
|
9
|
+
export interface QueueRouteOptions extends Omit<RouteOptions, 'protocol' | 'protocolOptions'> {
|
|
10
|
+
queue: string
|
|
11
|
+
reply?: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Declare a backend route carried by a queue. */
|
|
15
|
+
export const job = (
|
|
16
|
+
opts: QueueRouteOptions,
|
|
17
|
+
secondary?: Omit<QueueRouteOptions, 'queue'>,
|
|
18
|
+
): Partial<RouteOptions> => {
|
|
19
|
+
const { queue, reply, ...routeOptions } = { ...opts, ...secondary }
|
|
20
|
+
const declaration = backend(routeOptions)
|
|
21
|
+
declaration.protocol = QUEUE_PROTOCOL
|
|
22
|
+
declaration.protocolOptions = { queue, ...(reply == null ? {} : { reply }) }
|
|
23
|
+
return declaration
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Whether a declaration belongs to the queue transport. */
|
|
27
|
+
export const isQueueRoute = (route: RouteDeclaration | RouteModel): boolean =>
|
|
28
|
+
('route' in route ? route.route : route).protocol === QUEUE_PROTOCOL
|
|
29
|
+
|
|
30
|
+
/** Read and validate queue-owned route options. */
|
|
31
|
+
export const queueRouteOptions = (
|
|
32
|
+
route: RouteDeclaration | RouteModel,
|
|
33
|
+
): Pick<QueueRouteOptions, 'queue' | 'reply'> => {
|
|
34
|
+
const declaration = 'route' in route ? route.route : route
|
|
35
|
+
if (declaration.protocol !== QUEUE_PROTOCOL
|
|
36
|
+
|| declaration.protocolOptions == null
|
|
37
|
+
|| typeof declaration.protocolOptions !== 'object') {
|
|
38
|
+
throw new UnknownQueue(`${declaration.alias}: not a queue protocol`)
|
|
39
|
+
}
|
|
40
|
+
const options = declaration.protocolOptions as Record<string, unknown>
|
|
41
|
+
if (typeof options.queue !== 'string' || options.queue.trim() === '') {
|
|
42
|
+
throw new UnknownQueue(`${declaration.alias}: route declares no queue`)
|
|
43
|
+
}
|
|
44
|
+
if (options.reply != null && typeof options.reply !== 'boolean') {
|
|
45
|
+
throw new UnknownQueue(`${declaration.alias}: invalid queue reply option`)
|
|
46
|
+
}
|
|
47
|
+
return { queue: options.queue, reply: options.reply as boolean | undefined }
|
|
48
|
+
}
|
package/src/transport.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { assertContext, createService } from '@owlmeans/context'
|
|
2
2
|
import type { AbstractRequest, AbstractResponse, EntrypointTransport } from '@owlmeans/entrypoint'
|
|
3
3
|
import { EntrypointOutcome, transportAlias } from '@owlmeans/entrypoint'
|
|
4
|
-
import { RouteProtocols } from '@owlmeans/route'
|
|
5
4
|
import { ResilientError } from '@owlmeans/error'
|
|
6
5
|
import type { CommonEntrypoint } from '@owlmeans/entrypoint'
|
|
7
6
|
import type { Config, Context, JobEnvelope, JobReply, QueueAppend } from './types.js'
|
|
8
7
|
import { DEFAULT_JOB_TIMEOUT } from './consts.js'
|
|
9
|
-
import {
|
|
8
|
+
import { QUEUE_PROTOCOL, queueRouteOptions } from './route.js'
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* The producing half of the bridge: it turns a call on a QUEUE entrypoint into a job, and the
|
|
@@ -18,22 +17,20 @@ import { UnknownQueue } from './errors.js'
|
|
|
18
17
|
* the request rather than from the entrypoint: the far side rebuilds a request, and anything only
|
|
19
18
|
* HTTP understands would not survive the trip anyway.
|
|
20
19
|
*/
|
|
21
|
-
export const makeQueueTransport = (alias: string = transportAlias(
|
|
20
|
+
export const makeQueueTransport = (alias: string = transportAlias(QUEUE_PROTOCOL)) => {
|
|
22
21
|
const location = `queue-transport:${alias}`
|
|
23
22
|
|
|
24
23
|
const service = createService<EntrypointTransport>(alias, {
|
|
25
|
-
protocol:
|
|
24
|
+
protocol: QUEUE_PROTOCOL,
|
|
26
25
|
|
|
27
26
|
handle: (async <T>(req: AbstractRequest, res: AbstractResponse<T>) => {
|
|
28
27
|
const context = assertContext<Config, Context<Config>>(service.ctx as Context<Config>, location)
|
|
29
28
|
const entrypoint = context.entrypoint<CommonEntrypoint>(req.alias)
|
|
30
29
|
const route = entrypoint.route.route
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
throw new UnknownQueue(`${req.alias}: route declares no queue`)
|
|
34
|
-
}
|
|
31
|
+
const { queue, reply: waitsForReply } = queueRouteOptions(route)
|
|
35
32
|
|
|
36
|
-
const jobs = (context as unknown as QueueAppend).jobs<JobEnvelope, JobReply<T>>(
|
|
33
|
+
const jobs = (context as unknown as QueueAppend).jobs<JobEnvelope, JobReply<T>>(queue)
|
|
37
34
|
|
|
38
35
|
const envelope: JobEnvelope = {
|
|
39
36
|
alias: req.alias,
|
|
@@ -44,12 +41,12 @@ export const makeQueueTransport = (alias: string = transportAlias(RouteProtocols
|
|
|
44
41
|
enqueuedAt: new Date().toISOString(),
|
|
45
42
|
}
|
|
46
43
|
|
|
47
|
-
const job = await jobs.create({ queue
|
|
44
|
+
const job = await jobs.create({ queue, name: req.alias, data: envelope })
|
|
48
45
|
|
|
49
46
|
// `reply: false` says the caller is not waiting for the work, only for the promise that it
|
|
50
47
|
// was taken. `Accepted` plus the job's identity is the whole answer — enough to watch it.
|
|
51
|
-
if (
|
|
52
|
-
res.resolve({ id: job.id, queue
|
|
48
|
+
if (waitsForReply === false) {
|
|
49
|
+
res.resolve({ id: job.id, queue } as T, EntrypointOutcome.Accepted)
|
|
53
50
|
|
|
54
51
|
return
|
|
55
52
|
}
|
package/src/worker.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Middleware } from '@owlmeans/context'
|
|
2
2
|
import { MiddlewareStage, MiddlewareType, AppType } from '@owlmeans/context'
|
|
3
3
|
import type { CommonEntrypoint } from '@owlmeans/entrypoint'
|
|
4
|
-
import { RouteProtocols } from '@owlmeans/route'
|
|
5
4
|
import type { Config, Context, JobContext, JobEnvelope, JobProcessor, QueueWorkerService } from './types.js'
|
|
6
5
|
import { handleJob } from './bridge.js'
|
|
7
6
|
import { DEFAULT_ALIAS } from './consts.js'
|
|
7
|
+
import { isQueueRoute, queueRouteOptions } from './route.js'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Every queued entrypoint this process both SERVES and LISTENS to, grouped by queue.
|
|
@@ -22,17 +22,18 @@ export const servedJobs = <C extends Config, T extends Context<C>>(
|
|
|
22
22
|
|
|
23
23
|
context.entrypoints<CommonEntrypoint>().forEach(entrypoint => {
|
|
24
24
|
const route = entrypoint.route.route
|
|
25
|
-
if (route.type !== AppType.Backend || route
|
|
25
|
+
if (route.type !== AppType.Backend || !isQueueRoute(route)) {
|
|
26
26
|
return
|
|
27
27
|
}
|
|
28
28
|
if (route.service != null && route.service !== context.cfg.service) {
|
|
29
29
|
return
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
const { queue } = queueRouteOptions(route)
|
|
32
|
+
if (entrypoint.handle == null || !listen.includes(queue)) {
|
|
32
33
|
return
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
served.set(
|
|
36
|
+
served.set(queue, [...(served.get(queue) ?? []), entrypoint])
|
|
36
37
|
})
|
|
37
38
|
|
|
38
39
|
return served
|
package/tests/protocol.spec.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
2
|
import { contract, protocol, schema } from '@owlmeans/entrypoint'
|
|
3
|
-
import {
|
|
3
|
+
import { route } from '@owlmeans/route'
|
|
4
4
|
import type { JSONSchemaType } from 'ajv'
|
|
5
|
-
import { enqueueProtocol, waitForProtocol, type JobRecord } from '../src/index.js'
|
|
5
|
+
import { enqueueProtocol, job, waitForProtocol, type JobRecord } from '../src/index.js'
|
|
6
6
|
|
|
7
7
|
interface Input { value: number }
|
|
8
8
|
interface Output { doubled: number }
|