@btravstack/amqp-worker 0.9.0 → 0.10.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 +6 -2
- package/dist/index.cjs +32 -14
- package/dist/index.mjs +34 -16
- package/package.json +13 -13
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
15
|
pnpm add @btravstack/amqp-worker @btravstack/core @btravstack/config @btravstack/di unthrown \
|
|
16
|
-
@amqp-contract/worker @opentelemetry/api
|
|
16
|
+
@amqp-contract/worker@^3.0.0-beta.7 @opentelemetry/api
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
All six are peer dependencies — install them (`@opentelemetry/api` because
|
|
@@ -53,7 +53,7 @@ import { ErrAsync, OkAsync, P } from "unthrown";
|
|
|
53
53
|
const orderHandlers = AmqpHandlers(orderContract)({
|
|
54
54
|
inject: { placeOrder: PlaceOrder },
|
|
55
55
|
sync: ({ placeOrder }) => ({
|
|
56
|
-
orderNotifications: (message) =>
|
|
56
|
+
orderNotifications: ({ input: message }) =>
|
|
57
57
|
placeOrder
|
|
58
58
|
.execute(
|
|
59
59
|
TenantId(message.payload.tenantId),
|
|
@@ -106,6 +106,10 @@ pieces' ports, not what they close over. Two slices claiming one key are di's
|
|
|
106
106
|
duplicate-provider defect at build, which is the point: a consumer belongs to
|
|
107
107
|
exactly one slice.
|
|
108
108
|
|
|
109
|
+
Its own test suite needs a **Docker daemon**: the specs run against the shared
|
|
110
|
+
`rabbitmq` container `internal/test-infra` starts once per machine and every
|
|
111
|
+
workspace reuses. Nothing else here does.
|
|
112
|
+
|
|
109
113
|
## Options
|
|
110
114
|
|
|
111
115
|
`AmqpModule(name)({...})` takes `amqp()`'s options plus `handlers` and the
|
package/dist/index.cjs
CHANGED
|
@@ -34,7 +34,17 @@ const AmqpHandler = (contract, key) => {
|
|
|
34
34
|
* handler that must stop when the kernel stops waiting reads
|
|
35
35
|
* `currentUnit()?.signal`.
|
|
36
36
|
*/
|
|
37
|
-
const messageUnits = (host
|
|
37
|
+
const messageUnits = (host, observers) => (args, next) => {
|
|
38
|
+
const settle = (0, _btravstack_core.observe)(observers, {
|
|
39
|
+
component: "amqp",
|
|
40
|
+
name: "delivery",
|
|
41
|
+
attributes: { handler: args.handlerName }
|
|
42
|
+
});
|
|
43
|
+
return host.run(metaFor(args.rawMessage), () => next()).tap(() => settle({ outcome: "ok" })).tapFailure((failure) => settle({
|
|
44
|
+
outcome: "error",
|
|
45
|
+
cause: failure.tag === "Err" ? failure.error : failure.cause
|
|
46
|
+
}));
|
|
47
|
+
};
|
|
38
48
|
/**
|
|
39
49
|
* `UnitMeta.id` must be unique per unit, and a **delivery tag is not one**: tags
|
|
40
50
|
* are per-channel and restart at `1` after a reconnect, which
|
|
@@ -115,17 +125,25 @@ const amqp = (options) => {
|
|
|
115
125
|
}));
|
|
116
126
|
return (0, _btravstack_di.Module)("Amqp")({
|
|
117
127
|
needs: [_btravstack_config.Env, AmqpHandlersPort],
|
|
118
|
-
provides: [
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
128
|
+
provides: [
|
|
129
|
+
config,
|
|
130
|
+
_btravstack_di.Provider.member(_btravstack_core.Observers)({
|
|
131
|
+
inject: {},
|
|
132
|
+
value: _btravstack_core.noObserver
|
|
133
|
+
}),
|
|
134
|
+
(0, _btravstack_di.Provider)(AmqpRuntime)({
|
|
135
|
+
inject: {
|
|
136
|
+
config: AmqpConfig,
|
|
137
|
+
handlers: AmqpHandlersPort,
|
|
138
|
+
observers: _btravstack_core.Observers
|
|
139
|
+
},
|
|
140
|
+
sync: ({ config: bound, handlers, observers }) => ({
|
|
141
|
+
name: "amqp",
|
|
142
|
+
resolves: [],
|
|
143
|
+
start: (host) => createWorker(host, bound, options, handlers, observers)
|
|
144
|
+
})
|
|
127
145
|
})
|
|
128
|
-
|
|
146
|
+
],
|
|
129
147
|
exports: [AmqpRuntime, AmqpConfig]
|
|
130
148
|
});
|
|
131
149
|
};
|
|
@@ -165,15 +183,15 @@ const queuesOf = (contract) => [...new Set(Object.values({
|
|
|
165
183
|
...contract.consumers,
|
|
166
184
|
...contract.rpcs
|
|
167
185
|
}).map((entry) => entry.queue.name))].sort();
|
|
168
|
-
const createWorker = (host, config, options, handlers) => _amqp_contract_worker.TypedAmqpWorker.create({
|
|
186
|
+
const createWorker = (host, config, options, handlers, observers) => _amqp_contract_worker.TypedAmqpWorker.create({
|
|
169
187
|
contract: options.contract,
|
|
170
188
|
handlers,
|
|
171
|
-
middleware: messageUnits(host),
|
|
189
|
+
middleware: messageUnits(host, observers),
|
|
172
190
|
urls: [config.url],
|
|
173
191
|
...options.connectionOptions === void 0 ? {} : { connectionOptions: options.connectionOptions },
|
|
174
192
|
...options.defaultConsumerOptions === void 0 ? {} : { defaultConsumerOptions: options.defaultConsumerOptions },
|
|
175
193
|
connectTimeoutMs: config.connectTimeoutMs
|
|
176
|
-
}).map((worker) => consume(worker, queuesOf(options.contract))).
|
|
194
|
+
}).map((worker) => consume(worker, queuesOf(options.contract))).mapErrCases((matcher) => matcher.with(unthrown.P.tag("@amqp-contract/ConnectionError"), (error) => startFailed(error)));
|
|
177
195
|
const consume = (worker, queues) => {
|
|
178
196
|
let closing;
|
|
179
197
|
const beginClose = () => closing ??= worker.close({ drainTimeoutMs: null });
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Module, Port, Provider } from "@btravstack/di";
|
|
2
2
|
import { TypedAmqpWorker } from "@amqp-contract/worker";
|
|
3
3
|
import { Config, Env } from "@btravstack/config";
|
|
4
|
-
import { RuntimePort, RuntimeStartFailed, releasedBy } from "@btravstack/core";
|
|
5
|
-
import {
|
|
4
|
+
import { Observers, RuntimePort, RuntimeStartFailed, noObserver, observe, releasedBy } from "@btravstack/core";
|
|
5
|
+
import { P } from "unthrown";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
7
|
//#region src/handler.ts
|
|
8
8
|
/** The prefix a piece's port id carries; the composing form strips it to recover the key. */
|
|
@@ -33,7 +33,17 @@ const AmqpHandler = (contract, key) => {
|
|
|
33
33
|
* handler that must stop when the kernel stops waiting reads
|
|
34
34
|
* `currentUnit()?.signal`.
|
|
35
35
|
*/
|
|
36
|
-
const messageUnits = (host
|
|
36
|
+
const messageUnits = (host, observers) => (args, next) => {
|
|
37
|
+
const settle = observe(observers, {
|
|
38
|
+
component: "amqp",
|
|
39
|
+
name: "delivery",
|
|
40
|
+
attributes: { handler: args.handlerName }
|
|
41
|
+
});
|
|
42
|
+
return host.run(metaFor(args.rawMessage), () => next()).tap(() => settle({ outcome: "ok" })).tapFailure((failure) => settle({
|
|
43
|
+
outcome: "error",
|
|
44
|
+
cause: failure.tag === "Err" ? failure.error : failure.cause
|
|
45
|
+
}));
|
|
46
|
+
};
|
|
37
47
|
/**
|
|
38
48
|
* `UnitMeta.id` must be unique per unit, and a **delivery tag is not one**: tags
|
|
39
49
|
* are per-channel and restart at `1` after a reconnect, which
|
|
@@ -114,17 +124,25 @@ const amqp = (options) => {
|
|
|
114
124
|
}));
|
|
115
125
|
return Module("Amqp")({
|
|
116
126
|
needs: [Env, AmqpHandlersPort],
|
|
117
|
-
provides: [
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
provides: [
|
|
128
|
+
config,
|
|
129
|
+
Provider.member(Observers)({
|
|
130
|
+
inject: {},
|
|
131
|
+
value: noObserver
|
|
132
|
+
}),
|
|
133
|
+
Provider(AmqpRuntime)({
|
|
134
|
+
inject: {
|
|
135
|
+
config: AmqpConfig,
|
|
136
|
+
handlers: AmqpHandlersPort,
|
|
137
|
+
observers: Observers
|
|
138
|
+
},
|
|
139
|
+
sync: ({ config: bound, handlers, observers }) => ({
|
|
140
|
+
name: "amqp",
|
|
141
|
+
resolves: [],
|
|
142
|
+
start: (host) => createWorker(host, bound, options, handlers, observers)
|
|
143
|
+
})
|
|
126
144
|
})
|
|
127
|
-
|
|
145
|
+
],
|
|
128
146
|
exports: [AmqpRuntime, AmqpConfig]
|
|
129
147
|
});
|
|
130
148
|
};
|
|
@@ -164,15 +182,15 @@ const queuesOf = (contract) => [...new Set(Object.values({
|
|
|
164
182
|
...contract.consumers,
|
|
165
183
|
...contract.rpcs
|
|
166
184
|
}).map((entry) => entry.queue.name))].sort();
|
|
167
|
-
const createWorker = (host, config, options, handlers) => TypedAmqpWorker.create({
|
|
185
|
+
const createWorker = (host, config, options, handlers, observers) => TypedAmqpWorker.create({
|
|
168
186
|
contract: options.contract,
|
|
169
187
|
handlers,
|
|
170
|
-
middleware: messageUnits(host),
|
|
188
|
+
middleware: messageUnits(host, observers),
|
|
171
189
|
urls: [config.url],
|
|
172
190
|
...options.connectionOptions === void 0 ? {} : { connectionOptions: options.connectionOptions },
|
|
173
191
|
...options.defaultConsumerOptions === void 0 ? {} : { defaultConsumerOptions: options.defaultConsumerOptions },
|
|
174
192
|
connectTimeoutMs: config.connectTimeoutMs
|
|
175
|
-
}).map((worker) => consume(worker, queuesOf(options.contract))).
|
|
193
|
+
}).map((worker) => consume(worker, queuesOf(options.contract))).mapErrCases((matcher) => matcher.with(P.tag("@amqp-contract/ConnectionError"), (error) => startFailed(error)));
|
|
176
194
|
const consume = (worker, queues) => {
|
|
177
195
|
let closing;
|
|
178
196
|
const beginClose = () => closing ??= worker.close({ drainTimeoutMs: null });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btravstack/amqp-worker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "The AMQP starter for @btravstack/core: the handlers as a port, one unit per delivery, and a drain the kernel's deadline releases",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"amqp",
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
"./package.json": "./package.json"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@amqp-contract/contract": "3.0.0-beta.
|
|
48
|
-
"@amqp-contract/testing": "3.0.0-beta.
|
|
49
|
-
"@amqp-contract/worker": "3.0.0-beta.
|
|
47
|
+
"@amqp-contract/contract": "3.0.0-beta.7",
|
|
48
|
+
"@amqp-contract/testing": "3.0.0-beta.7",
|
|
49
|
+
"@amqp-contract/worker": "3.0.0-beta.7",
|
|
50
50
|
"@btravstack/tsconfig": "0.2.0",
|
|
51
51
|
"@opentelemetry/api": "1.9.1",
|
|
52
52
|
"@types/node": "26.4.0",
|
|
@@ -56,20 +56,20 @@
|
|
|
56
56
|
"typescript": "7.0.2",
|
|
57
57
|
"unthrown": "5.7.0",
|
|
58
58
|
"vitest": "4.1.11",
|
|
59
|
-
"zod": "4.5.
|
|
60
|
-
"@btravstack/config": "0.
|
|
61
|
-
"@btravstack/core": "0.
|
|
62
|
-
"@btravstack/di": "0.
|
|
59
|
+
"zod": "4.5.3",
|
|
60
|
+
"@btravstack/config": "0.10.0",
|
|
61
|
+
"@btravstack/core": "0.10.0",
|
|
62
|
+
"@btravstack/di": "0.10.0",
|
|
63
63
|
"@btravstack/internal-test-infra": "0.0.0",
|
|
64
|
-
"@btravstack/testing": "0.
|
|
64
|
+
"@btravstack/testing": "0.10.0"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@amqp-contract/worker": "^3.0.0-beta.
|
|
67
|
+
"@amqp-contract/worker": "^3.0.0-beta.7",
|
|
68
68
|
"@opentelemetry/api": "^1",
|
|
69
69
|
"unthrown": "^5.0.0",
|
|
70
|
-
"@btravstack/config": "^0.
|
|
71
|
-
"@btravstack/core": "^0.
|
|
72
|
-
"@btravstack/di": "^0.
|
|
70
|
+
"@btravstack/config": "^0.10.0",
|
|
71
|
+
"@btravstack/core": "^0.10.0",
|
|
72
|
+
"@btravstack/di": "^0.10.0"
|
|
73
73
|
},
|
|
74
74
|
"engines": {
|
|
75
75
|
"node": ">=22"
|