@voltro/plugin-queue 0.84.0 → 0.86.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/dist/runner.js ADDED
@@ -0,0 +1,109 @@
1
+ import { recordQueueConsumed as e, recordQueueDeadLettered as t, recordQueueRetry as n } from "./queueMetrics.js";
2
+ import { runInQueueMessageSpan as r } from "./queueTracing.js";
3
+ import { Result as i, Schema as a } from "effect";
4
+ //#region src/runner.ts
5
+ var o = (e) => new Promise((t) => setTimeout(t, e)), s = async (s) => {
6
+ let { provider: c, log: l } = s, u = { current: !1 }, d = /* @__PURE__ */ new Set(), f = async (u) => {
7
+ let d = u.groupId ?? `${s.appName}.${u.topic}`, f = u.dlqTopic ?? `${u.topic}.dlq`, p = u.maxAttempts ?? 3, m = a.decodeUnknownResult(u.schema), h = async (e, n, r) => {
8
+ t(u.topic, `${e}: ${n}`), l.warn("queue: dead-lettered", {
9
+ topic: u.topic,
10
+ dlqTopic: f,
11
+ reason: e,
12
+ partition: r.partition,
13
+ offset: r.offset
14
+ }), await c.produce(f, [{
15
+ ...r.key === null ? {} : { key: r.key },
16
+ value: r.value ?? "",
17
+ headers: {
18
+ ...r.headers,
19
+ "x-voltro-dlq-reason": e,
20
+ "x-voltro-dlq-detail": n.slice(0, 500),
21
+ "x-voltro-dlq-source-topic": r.topic,
22
+ "x-voltro-dlq-source-partition": String(r.partition),
23
+ "x-voltro-dlq-source-offset": r.offset
24
+ }
25
+ }]);
26
+ }, g = await c.consume({
27
+ topic: u.topic,
28
+ groupId: d,
29
+ ...u.fromBeginning === void 0 ? {} : { fromBeginning: u.fromBeginning },
30
+ onMessage: async (t, a) => {
31
+ await r({
32
+ system: c.name,
33
+ topic: u.topic,
34
+ groupId: d,
35
+ partition: t.partition,
36
+ offset: t.offset,
37
+ traceparent: t.headers.traceparent
38
+ }, async () => {
39
+ let r;
40
+ try {
41
+ r = t.value === null ? null : JSON.parse(t.value);
42
+ } catch (e) {
43
+ return await h("decode-failed", `invalid JSON: ${e instanceof Error ? e.message : String(e)}`, t), "dead-lettered";
44
+ }
45
+ let c = m(r);
46
+ if (i.isFailure(c)) return await h("decode-failed", String(c.failure), t), "dead-lettered";
47
+ for (let r = 1; r <= p; r++) {
48
+ if (a.isStale()) return "stale";
49
+ try {
50
+ return await u.handler(c.success, {
51
+ topic: t.topic,
52
+ partition: t.partition,
53
+ offset: t.offset,
54
+ key: t.key,
55
+ headers: t.headers,
56
+ attempt: r,
57
+ ...t.headers.traceparent === void 0 ? {} : { traceparent: t.headers.traceparent },
58
+ get store() {
59
+ let e = s.store();
60
+ if (e === null) throw Error("queue: store not bound yet — the retry loop absorbs a message arriving before boot finished");
61
+ return e;
62
+ }
63
+ }), e(u.topic), "ok";
64
+ } catch (e) {
65
+ let i = e instanceof Error ? e.message : String(e);
66
+ if (r >= p) return await h("handler-failed", i, t), "dead-lettered";
67
+ n(u.topic), l.warn("queue: handler failed, retrying", {
68
+ topic: u.topic,
69
+ attempt: r,
70
+ maxAttempts: p,
71
+ detail: i
72
+ }), await a.heartbeat().catch(() => {}), await o((s.retryBaseMs ?? 1e3) * 2 ** (r - 1));
73
+ }
74
+ }
75
+ return "stale";
76
+ }, (e) => ({ "voltro.queue.outcome": e }));
77
+ }
78
+ });
79
+ return l.info("queue: consumer started", {
80
+ topic: u.topic,
81
+ groupId: d,
82
+ dlqTopic: f
83
+ }), g;
84
+ }, p = s.consumers.map((e) => {
85
+ let t = { handle: null }, n = () => {
86
+ f(e).then((e) => {
87
+ u.current ? e.stop() : t.handle = e;
88
+ }).catch((t) => {
89
+ if (u.current) return;
90
+ l.warn("queue: consumer start failed — retrying in 5s", {
91
+ topic: e.topic,
92
+ detail: t instanceof Error ? t.message : String(t)
93
+ });
94
+ let r = setTimeout(() => {
95
+ d.delete(r), n();
96
+ }, 5e3);
97
+ d.add(r);
98
+ });
99
+ };
100
+ return n(), t;
101
+ });
102
+ return { stop: async () => {
103
+ u.current = !0;
104
+ for (let e of d) clearTimeout(e);
105
+ d.clear(), await Promise.all(p.map((e) => e.handle?.stop() ?? Promise.resolve()));
106
+ } };
107
+ };
108
+ //#endregion
109
+ export { s as startQueueConsumers };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/plugin-queue",
3
- "version": "0.84.0",
3
+ "version": "0.86.0",
4
4
  "description": "Queue interop — consume and produce against an existing Kafka: Schema-decoded consumers via defineQueueConsumer (*.consumer.ts; at-least-once, serial per partition, retry + dead-letter), batched producing via QueueService or transactionally through the outbox (queueOutboxHandler), and a kafkaSink for plugin-cdc-out.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -33,13 +33,13 @@
33
33
  "node": ">=24.0.0"
34
34
  },
35
35
  "dependencies": {
36
- "@voltro/database": "0.84.0",
37
- "@voltro/protocol": "0.84.0",
38
- "@voltro/runtime": "0.84.0",
36
+ "@voltro/database": "0.86.0",
37
+ "@voltro/protocol": "0.86.0",
38
+ "@voltro/runtime": "0.86.0",
39
39
  "kafkajs": "^2.2.4"
40
40
  },
41
41
  "peerDependencies": {
42
- "effect": "^3.22.2"
42
+ "effect": "4.0.1"
43
43
  },
44
44
  "publishConfig": {
45
45
  "access": "public"