@boringnode/queue 0.5.0 → 0.5.1
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 +71 -0
- package/build/{chunk-WOUYSNK2.js → chunk-KI47AJ6U.js} +2 -2
- package/build/chunk-PZ5AY32C.js +10 -0
- package/build/chunk-PZ5AY32C.js.map +1 -0
- package/build/{chunk-ZZFSQY36.js → chunk-QEFYHCL7.js} +4 -6
- package/build/{chunk-ZZFSQY36.js.map → chunk-QEFYHCL7.js.map} +1 -1
- package/build/{chunk-OVYXMSSU.js → chunk-VHN3XZDC.js} +54 -16
- package/build/chunk-VHN3XZDC.js.map +1 -0
- package/build/chunk-WVLSICD4.js +20 -0
- package/build/chunk-WVLSICD4.js.map +1 -0
- package/build/index.d.ts +37 -4
- package/build/index.js +64 -51
- package/build/index.js.map +1 -1
- package/build/{index-B1XdqWpN.d.ts → job-DImdhRFO.d.ts} +16 -1
- package/build/src/contracts/adapter.d.ts +1 -1
- package/build/src/drivers/fake_adapter.d.ts +1 -1
- package/build/src/drivers/fake_adapter.js +4 -2
- package/build/src/drivers/knex_adapter.d.ts +1 -1
- package/build/src/drivers/knex_adapter.js +2 -1
- package/build/src/drivers/knex_adapter.js.map +1 -1
- package/build/src/drivers/redis_adapter.d.ts +1 -1
- package/build/src/drivers/redis_adapter.js +2 -1
- package/build/src/drivers/redis_adapter.js.map +1 -1
- package/build/src/drivers/sync_adapter.d.ts +1 -1
- package/build/src/drivers/sync_adapter.js +38 -18
- package/build/src/drivers/sync_adapter.js.map +1 -1
- package/build/src/otel.d.ts +63 -0
- package/build/src/otel.js +242 -0
- package/build/src/otel.js.map +1 -0
- package/build/src/types/index.d.ts +6 -1
- package/build/src/types/main.d.ts +1 -1
- package/build/src/types/tracing_channels.d.ts +34 -0
- package/build/src/types/tracing_channels.js +1 -0
- package/build/src/types/tracing_channels.js.map +1 -0
- package/package.json +35 -12
- package/build/chunk-OVYXMSSU.js.map +0 -1
- /package/build/{chunk-WOUYSNK2.js.map → chunk-KI47AJ6U.js.map} +0 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import {
|
|
2
|
+
dispatchChannel,
|
|
3
|
+
executeChannel
|
|
4
|
+
} from "../chunk-WVLSICD4.js";
|
|
5
|
+
import "../chunk-PZ5AY32C.js";
|
|
6
|
+
|
|
7
|
+
// src/otel.ts
|
|
8
|
+
import {
|
|
9
|
+
context,
|
|
10
|
+
propagation,
|
|
11
|
+
trace,
|
|
12
|
+
SpanKind,
|
|
13
|
+
SpanStatusCode,
|
|
14
|
+
ROOT_CONTEXT
|
|
15
|
+
} from "@opentelemetry/api";
|
|
16
|
+
import { suppressTracing } from "@opentelemetry/core";
|
|
17
|
+
import { InstrumentationBase } from "@opentelemetry/instrumentation";
|
|
18
|
+
var QueueInstrumentation = class extends InstrumentationBase {
|
|
19
|
+
subscribed = false;
|
|
20
|
+
executeSpans = /* @__PURE__ */ new Map();
|
|
21
|
+
dispatchSpans = /* @__PURE__ */ new WeakMap();
|
|
22
|
+
executeHandlers;
|
|
23
|
+
dispatchHandlers;
|
|
24
|
+
#originalInit;
|
|
25
|
+
#patchedManager;
|
|
26
|
+
constructor(config = {}) {
|
|
27
|
+
super("@boringnode/queue", "0.1.0", config);
|
|
28
|
+
}
|
|
29
|
+
get #messagingSystem() {
|
|
30
|
+
return this.getConfig().messagingSystem ?? "boringqueue";
|
|
31
|
+
}
|
|
32
|
+
get #executionSpanLinkMode() {
|
|
33
|
+
return this.getConfig().executionSpanLinkMode ?? "link";
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Required by InstrumentationBase. Returns undefined since we use
|
|
37
|
+
* diagnostics_channel instead of module patching.
|
|
38
|
+
*/
|
|
39
|
+
init() {
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Subscribes to diagnostics_channels for span lifecycle.
|
|
44
|
+
*/
|
|
45
|
+
enable() {
|
|
46
|
+
super.enable();
|
|
47
|
+
if (this.subscribed !== void 0) this.#subscribe();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Unsubscribes from diagnostics_channels and restores patched methods.
|
|
51
|
+
*/
|
|
52
|
+
disable() {
|
|
53
|
+
if (this.subscribed !== void 0) {
|
|
54
|
+
this.#unsubscribe();
|
|
55
|
+
this.#unpatchInit();
|
|
56
|
+
}
|
|
57
|
+
super.disable();
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Patches `QueueManager.init()` to auto-inject OTel wrappers
|
|
61
|
+
* and subscribes to diagnostics_channels.
|
|
62
|
+
*/
|
|
63
|
+
manuallyRegister(queueModule) {
|
|
64
|
+
this.#patchInit(queueModule.QueueManager);
|
|
65
|
+
this.#subscribe();
|
|
66
|
+
}
|
|
67
|
+
#patchInit(manager) {
|
|
68
|
+
if (this.#originalInit) return;
|
|
69
|
+
this.#patchedManager = manager;
|
|
70
|
+
this.#originalInit = manager.init.bind(manager);
|
|
71
|
+
const instrumentation = this;
|
|
72
|
+
manager.init = async (config) => {
|
|
73
|
+
return this.#originalInit({
|
|
74
|
+
...config,
|
|
75
|
+
internalOperationWrapper: (fn) => {
|
|
76
|
+
return context.with(suppressTracing(context.active()), fn);
|
|
77
|
+
},
|
|
78
|
+
executionWrapper: (fn, job, queue) => {
|
|
79
|
+
return instrumentation.#wrapExecution(fn, job, queue);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
#unpatchInit() {
|
|
85
|
+
if (!this.#originalInit || !this.#patchedManager) return;
|
|
86
|
+
this.#patchedManager.init = this.#originalInit;
|
|
87
|
+
this.#originalInit = void 0;
|
|
88
|
+
this.#patchedManager = void 0;
|
|
89
|
+
}
|
|
90
|
+
#subscribe() {
|
|
91
|
+
if (this.subscribed) return;
|
|
92
|
+
if (!this.isEnabled()) return;
|
|
93
|
+
this.subscribed = true;
|
|
94
|
+
this.executeHandlers = {
|
|
95
|
+
start: () => {
|
|
96
|
+
},
|
|
97
|
+
end: () => {
|
|
98
|
+
},
|
|
99
|
+
asyncStart: () => {
|
|
100
|
+
},
|
|
101
|
+
asyncEnd: (msg) => this.#handleExecuteAsyncEnd(msg),
|
|
102
|
+
error: () => {
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
this.dispatchHandlers = {
|
|
106
|
+
start: (msg) => this.#handleDispatchStart(msg),
|
|
107
|
+
end: () => {
|
|
108
|
+
},
|
|
109
|
+
asyncStart: () => {
|
|
110
|
+
},
|
|
111
|
+
asyncEnd: (msg) => this.#handleDispatchAsyncEnd(msg),
|
|
112
|
+
error: () => {
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
executeChannel.subscribe(this.executeHandlers);
|
|
116
|
+
dispatchChannel.subscribe(this.dispatchHandlers);
|
|
117
|
+
}
|
|
118
|
+
#unsubscribe() {
|
|
119
|
+
if (!this.subscribed) return;
|
|
120
|
+
if (this.executeHandlers) executeChannel.unsubscribe(this.executeHandlers);
|
|
121
|
+
if (this.dispatchHandlers) dispatchChannel.unsubscribe(this.dispatchHandlers);
|
|
122
|
+
this.subscribed = false;
|
|
123
|
+
this.executeHandlers = void 0;
|
|
124
|
+
this.dispatchHandlers = void 0;
|
|
125
|
+
this.executeSpans.clear();
|
|
126
|
+
this.dispatchSpans = /* @__PURE__ */ new WeakMap();
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Called on dispatchChannel `start` — injects trace context into jobData
|
|
130
|
+
* and creates/enriches a PRODUCER span.
|
|
131
|
+
*/
|
|
132
|
+
#handleDispatchStart(message) {
|
|
133
|
+
const attributes = this.#buildDispatchAttributes(message);
|
|
134
|
+
const span = this.tracer.startSpan(`publish ${message.queue}`, {
|
|
135
|
+
kind: SpanKind.PRODUCER,
|
|
136
|
+
attributes
|
|
137
|
+
});
|
|
138
|
+
const dispatchContext = trace.setSpan(context.active(), span);
|
|
139
|
+
for (const job of message.jobs) {
|
|
140
|
+
if (!job.traceContext) job.traceContext = {};
|
|
141
|
+
propagation.inject(dispatchContext, job.traceContext);
|
|
142
|
+
}
|
|
143
|
+
this.dispatchSpans.set(message, span);
|
|
144
|
+
}
|
|
145
|
+
#handleDispatchAsyncEnd(message) {
|
|
146
|
+
const span = this.dispatchSpans.get(message);
|
|
147
|
+
if (!span) return;
|
|
148
|
+
if (message.error) {
|
|
149
|
+
span.recordException(message.error);
|
|
150
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: message.error.message });
|
|
151
|
+
}
|
|
152
|
+
span.end();
|
|
153
|
+
this.dispatchSpans.delete(message);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Called by `executionWrapper` config — creates CONSUMER span and wraps
|
|
157
|
+
* execution in OTel context for proper child span parenting.
|
|
158
|
+
*/
|
|
159
|
+
#wrapExecution(fn, job, queue) {
|
|
160
|
+
const extractedContext = this.#extractParentContext(job.traceContext);
|
|
161
|
+
const parentSpanContext = trace.getSpanContext(extractedContext);
|
|
162
|
+
let baseContext;
|
|
163
|
+
let links;
|
|
164
|
+
if (this.#executionSpanLinkMode === "parent" && parentSpanContext) {
|
|
165
|
+
baseContext = extractedContext;
|
|
166
|
+
links = [];
|
|
167
|
+
} else {
|
|
168
|
+
links = parentSpanContext ? [{ context: parentSpanContext }] : [];
|
|
169
|
+
baseContext = ROOT_CONTEXT;
|
|
170
|
+
}
|
|
171
|
+
const span = this.tracer.startSpan(
|
|
172
|
+
`process ${queue}`,
|
|
173
|
+
{
|
|
174
|
+
kind: SpanKind.CONSUMER,
|
|
175
|
+
attributes: this.#buildExecuteAttributes(job, queue),
|
|
176
|
+
links
|
|
177
|
+
},
|
|
178
|
+
baseContext
|
|
179
|
+
);
|
|
180
|
+
this.executeSpans.set(job.id, span);
|
|
181
|
+
const executionContext = trace.setSpan(baseContext, span);
|
|
182
|
+
return context.with(executionContext, fn);
|
|
183
|
+
}
|
|
184
|
+
#handleExecuteAsyncEnd(message) {
|
|
185
|
+
const span = this.executeSpans.get(message.job.id);
|
|
186
|
+
if (!span) return;
|
|
187
|
+
if (message.status) span.setAttribute("messaging.job.status", message.status);
|
|
188
|
+
if (message.error) span.recordException(message.error);
|
|
189
|
+
if (message.status === "retrying" && message.nextRetryAt) {
|
|
190
|
+
span.addEvent("messaging.retry", {
|
|
191
|
+
"messaging.message.retry.count": message.job.attempts + 1,
|
|
192
|
+
"messaging.job.retry_at": message.nextRetryAt.toISOString()
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (message.status === "failed") {
|
|
196
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: message.error?.message });
|
|
197
|
+
} else {
|
|
198
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
199
|
+
}
|
|
200
|
+
span.end();
|
|
201
|
+
this.executeSpans.delete(message.job.id);
|
|
202
|
+
}
|
|
203
|
+
#extractParentContext(traceContext) {
|
|
204
|
+
if (!traceContext || Object.keys(traceContext).length === 0) return ROOT_CONTEXT;
|
|
205
|
+
return propagation.extract(ROOT_CONTEXT, traceContext);
|
|
206
|
+
}
|
|
207
|
+
#buildDispatchAttributes(message) {
|
|
208
|
+
const firstJob = message.jobs[0];
|
|
209
|
+
const attributes = {
|
|
210
|
+
"messaging.system": this.#messagingSystem,
|
|
211
|
+
"messaging.operation.name": "publish",
|
|
212
|
+
"messaging.operation.type": "send",
|
|
213
|
+
"messaging.destination.name": message.queue,
|
|
214
|
+
"messaging.job.name": firstJob.name
|
|
215
|
+
};
|
|
216
|
+
if (message.jobs.length === 1) attributes["messaging.message.id"] = firstJob.id;
|
|
217
|
+
if (message.jobs.length > 1) attributes["messaging.batch.message_count"] = message.jobs.length;
|
|
218
|
+
if (firstJob.groupId) attributes["messaging.job.group_id"] = firstJob.groupId;
|
|
219
|
+
if (firstJob.priority !== void 0) attributes["messaging.job.priority"] = firstJob.priority;
|
|
220
|
+
if (message.delay !== void 0) attributes["messaging.job.delay_ms"] = message.delay;
|
|
221
|
+
return attributes;
|
|
222
|
+
}
|
|
223
|
+
#buildExecuteAttributes(job, queue) {
|
|
224
|
+
const attributes = {
|
|
225
|
+
"entry_point.type": "job",
|
|
226
|
+
"messaging.system": this.#messagingSystem,
|
|
227
|
+
"messaging.operation.name": "process",
|
|
228
|
+
"messaging.operation.type": "process",
|
|
229
|
+
"messaging.destination.name": queue,
|
|
230
|
+
"messaging.message.id": job.id,
|
|
231
|
+
"messaging.message.retry.count": job.attempts,
|
|
232
|
+
"messaging.job.name": job.name
|
|
233
|
+
};
|
|
234
|
+
if (job.groupId) attributes["messaging.job.group_id"] = job.groupId;
|
|
235
|
+
if (job.priority !== void 0) attributes["messaging.job.priority"] = job.priority;
|
|
236
|
+
return attributes;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
export {
|
|
240
|
+
QueueInstrumentation
|
|
241
|
+
};
|
|
242
|
+
//# sourceMappingURL=otel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/otel.ts"],"sourcesContent":["import {\n context,\n propagation,\n trace,\n SpanKind,\n SpanStatusCode,\n ROOT_CONTEXT,\n type Span,\n type Link,\n} from '@opentelemetry/api'\nimport type { TracingChannelSubscribers } from 'node:diagnostics_channel'\nimport { suppressTracing } from '@opentelemetry/core'\nimport { InstrumentationBase } from '@opentelemetry/instrumentation'\nimport type { InstrumentationConfig } from '@opentelemetry/instrumentation'\nimport { dispatchChannel, executeChannel } from './tracing_channels.js'\nimport type { AcquiredJob } from './contracts/adapter.js'\nimport type { JobDispatchMessage, JobExecuteMessage } from './types/tracing_channels.js'\n\nexport interface QueueInstrumentationConfig extends InstrumentationConfig {\n /**\n * How execution spans relate to the dispatch span.\n *\n * - `'link'` (default): Independent trace, linked to dispatch span\n * - `'parent'`: Child of the dispatch span (same trace)\n */\n executionSpanLinkMode?: 'link' | 'parent'\n\n /**\n * The messaging system identifier.\n *\n * @default 'boringqueue'\n */\n messagingSystem?: string\n}\n\n/**\n * OpenTelemetry instrumentation for @boringnode/queue.\n *\n * Creates PRODUCER spans for job dispatch and CONSUMER spans for\n * job execution, following OTel messaging semantic conventions.\n *\n * Uses `diagnostics_channel` for span lifecycle management and\n * patches `QueueManager.init()` to inject wrappers automatically.\n */\nexport class QueueInstrumentation extends InstrumentationBase<QueueInstrumentationConfig> {\n protected subscribed = false\n protected executeSpans = new Map<string, Span>()\n protected dispatchSpans = new WeakMap<JobDispatchMessage, Span>()\n protected executeHandlers?: TracingChannelSubscribers<JobExecuteMessage>\n protected dispatchHandlers?: TracingChannelSubscribers<JobDispatchMessage>\n\n #originalInit?: (...args: any[]) => any\n #patchedManager?: { init: (...args: any[]) => any }\n\n constructor(config: QueueInstrumentationConfig = {}) {\n super('@boringnode/queue', '0.1.0', config)\n }\n\n get #messagingSystem(): string {\n return this.getConfig().messagingSystem ?? 'boringqueue'\n }\n\n get #executionSpanLinkMode(): 'link' | 'parent' {\n return this.getConfig().executionSpanLinkMode ?? 'link'\n }\n\n /**\n * Required by InstrumentationBase. Returns undefined since we use\n * diagnostics_channel instead of module patching.\n */\n protected init() {\n return undefined\n }\n\n /**\n * Subscribes to diagnostics_channels for span lifecycle.\n */\n enable() {\n super.enable()\n if (this.subscribed !== undefined) this.#subscribe()\n }\n\n /**\n * Unsubscribes from diagnostics_channels and restores patched methods.\n */\n disable() {\n if (this.subscribed !== undefined) {\n this.#unsubscribe()\n this.#unpatchInit()\n }\n\n super.disable()\n }\n\n /**\n * Patches `QueueManager.init()` to auto-inject OTel wrappers\n * and subscribes to diagnostics_channels.\n */\n manuallyRegister(queueModule: { QueueManager: { init: (...args: any[]) => any } }) {\n this.#patchInit(queueModule.QueueManager)\n this.#subscribe()\n }\n\n #patchInit(manager: { init: (...args: any[]) => any }) {\n if (this.#originalInit) return\n\n this.#patchedManager = manager\n this.#originalInit = manager.init.bind(manager)\n const instrumentation = this\n\n manager.init = async (config: any) => {\n return this.#originalInit!({\n ...config,\n internalOperationWrapper: <T>(fn: () => Promise<T>) => {\n return context.with(suppressTracing(context.active()), fn)\n },\n executionWrapper: <T>(fn: () => Promise<T>, job: AcquiredJob, queue: string) => {\n return instrumentation.#wrapExecution(fn, job, queue)\n },\n })\n }\n }\n\n #unpatchInit() {\n if (!this.#originalInit || !this.#patchedManager) return\n\n this.#patchedManager.init = this.#originalInit\n this.#originalInit = undefined\n this.#patchedManager = undefined\n }\n\n #subscribe() {\n if (this.subscribed) return\n if (!this.isEnabled()) return\n\n this.subscribed = true\n\n this.executeHandlers = {\n start: () => {},\n end: () => {},\n asyncStart: () => {},\n asyncEnd: (msg) => this.#handleExecuteAsyncEnd(msg as unknown as JobExecuteMessage),\n error: () => {},\n }\n\n this.dispatchHandlers = {\n start: (msg) => this.#handleDispatchStart(msg as unknown as JobDispatchMessage),\n end: () => {},\n asyncStart: () => {},\n asyncEnd: (msg) => this.#handleDispatchAsyncEnd(msg as unknown as JobDispatchMessage),\n error: () => {},\n }\n\n executeChannel.subscribe(this.executeHandlers as any)\n dispatchChannel.subscribe(this.dispatchHandlers as any)\n }\n\n #unsubscribe() {\n if (!this.subscribed) return\n\n if (this.executeHandlers) executeChannel.unsubscribe(this.executeHandlers as any)\n if (this.dispatchHandlers) dispatchChannel.unsubscribe(this.dispatchHandlers as any)\n\n this.subscribed = false\n this.executeHandlers = undefined\n this.dispatchHandlers = undefined\n this.executeSpans.clear()\n this.dispatchSpans = new WeakMap()\n }\n\n /**\n * Called on dispatchChannel `start` — injects trace context into jobData\n * and creates/enriches a PRODUCER span.\n */\n #handleDispatchStart(message: JobDispatchMessage) {\n const attributes = this.#buildDispatchAttributes(message)\n const span = this.tracer.startSpan(`publish ${message.queue}`, {\n kind: SpanKind.PRODUCER,\n attributes,\n })\n\n const dispatchContext = trace.setSpan(context.active(), span)\n for (const job of message.jobs) {\n if (!job.traceContext) job.traceContext = {}\n propagation.inject(dispatchContext, job.traceContext)\n }\n\n this.dispatchSpans.set(message, span)\n }\n\n #handleDispatchAsyncEnd(message: JobDispatchMessage) {\n const span = this.dispatchSpans.get(message)\n if (!span) return\n\n if (message.error) {\n span.recordException(message.error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: message.error.message })\n }\n\n span.end()\n this.dispatchSpans.delete(message)\n }\n\n /**\n * Called by `executionWrapper` config — creates CONSUMER span and wraps\n * execution in OTel context for proper child span parenting.\n */\n #wrapExecution<T>(fn: () => Promise<T>, job: AcquiredJob, queue: string): Promise<T> {\n const extractedContext = this.#extractParentContext(job.traceContext)\n const parentSpanContext = trace.getSpanContext(extractedContext)\n\n let baseContext: typeof extractedContext\n let links: Link[]\n\n if (this.#executionSpanLinkMode === 'parent' && parentSpanContext) {\n baseContext = extractedContext\n links = []\n } else {\n links = parentSpanContext ? [{ context: parentSpanContext }] : []\n baseContext = ROOT_CONTEXT\n }\n\n const span = this.tracer.startSpan(\n `process ${queue}`,\n {\n kind: SpanKind.CONSUMER,\n attributes: this.#buildExecuteAttributes(job, queue),\n links,\n },\n baseContext\n )\n\n this.executeSpans.set(job.id, span)\n const executionContext = trace.setSpan(baseContext, span)\n\n return context.with(executionContext, fn)\n }\n\n #handleExecuteAsyncEnd(message: JobExecuteMessage) {\n const span = this.executeSpans.get(message.job.id)\n if (!span) return\n\n if (message.status) span.setAttribute('messaging.job.status', message.status)\n if (message.error) span.recordException(message.error)\n\n if (message.status === 'retrying' && message.nextRetryAt) {\n span.addEvent('messaging.retry', {\n 'messaging.message.retry.count': message.job.attempts + 1,\n 'messaging.job.retry_at': message.nextRetryAt.toISOString(),\n })\n }\n\n if (message.status === 'failed') {\n span.setStatus({ code: SpanStatusCode.ERROR, message: message.error?.message })\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n\n span.end()\n this.executeSpans.delete(message.job.id)\n }\n\n #extractParentContext(traceContext?: Record<string, string>) {\n if (!traceContext || Object.keys(traceContext).length === 0) return ROOT_CONTEXT\n return propagation.extract(ROOT_CONTEXT, traceContext)\n }\n\n #buildDispatchAttributes(message: JobDispatchMessage) {\n const firstJob = message.jobs[0]\n const attributes: Record<string, string | number | boolean> = {\n 'messaging.system': this.#messagingSystem,\n 'messaging.operation.name': 'publish',\n 'messaging.operation.type': 'send',\n 'messaging.destination.name': message.queue,\n 'messaging.job.name': firstJob.name,\n }\n\n if (message.jobs.length === 1) attributes['messaging.message.id'] = firstJob.id\n if (message.jobs.length > 1) attributes['messaging.batch.message_count'] = message.jobs.length\n if (firstJob.groupId) attributes['messaging.job.group_id'] = firstJob.groupId\n if (firstJob.priority !== undefined) attributes['messaging.job.priority'] = firstJob.priority\n if (message.delay !== undefined) attributes['messaging.job.delay_ms'] = message.delay\n\n return attributes\n }\n\n #buildExecuteAttributes(job: AcquiredJob, queue: string) {\n const attributes: Record<string, string | number | boolean> = {\n 'entry_point.type': 'job',\n 'messaging.system': this.#messagingSystem,\n 'messaging.operation.name': 'process',\n 'messaging.operation.type': 'process',\n 'messaging.destination.name': queue,\n 'messaging.message.id': job.id,\n 'messaging.message.retry.count': job.attempts,\n 'messaging.job.name': job.name,\n }\n\n if (job.groupId) attributes['messaging.job.group_id'] = job.groupId\n if (job.priority !== undefined) attributes['messaging.job.priority'] = job.priority\n\n return attributes\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1,6 @@
|
|
|
1
|
-
export { b as AcquiredJob, A as Adapter,
|
|
1
|
+
export { b as AcquiredJob, A as Adapter, r as AdapterFactory, B as BackoffConfig, s as BackoffStrategy, t as DispatchManyResult, u as DispatchResult, D as Duration, a as JobClass, v as JobContext, J as JobData, i as JobFactory, g as JobOptions, d as JobRecord, c as JobRetention, w as JobStatus, L as Logger, h as QueueConfig, Q as QueueManagerConfig, R as RetryConfig, S as ScheduleConfig, e as ScheduleData, f as ScheduleListOptions, x as ScheduleResult, k as ScheduleStatus, y as WorkerConfig, W as WorkerCycle } from '../../job-DImdhRFO.js';
|
|
2
|
+
export { JobDispatchMessage, JobExecuteMessage } from './tracing_channels.js';
|
|
3
|
+
export { QueueInstrumentationConfig } from '../otel.js';
|
|
4
|
+
import '@opentelemetry/api';
|
|
5
|
+
import 'node:diagnostics_channel';
|
|
6
|
+
import '@opentelemetry/instrumentation';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { r as AdapterFactory, B as BackoffConfig, s as BackoffStrategy, t as DispatchManyResult, u as DispatchResult, D as Duration, a as JobClass, v as JobContext, J as JobData, i as JobFactory, g as JobOptions, d as JobRecord, c as JobRetention, w as JobStatus, L as Logger, h as QueueConfig, Q as QueueManagerConfig, R as RetryConfig, S as ScheduleConfig, e as ScheduleData, f as ScheduleListOptions, x as ScheduleResult, k as ScheduleStatus, y as WorkerConfig, W as WorkerCycle } from '../../job-DImdhRFO.js';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { J as JobData, b as AcquiredJob } from '../../job-DImdhRFO.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tracing data structure for job dispatch events.
|
|
5
|
+
*/
|
|
6
|
+
type JobDispatchMessage = {
|
|
7
|
+
/** The jobs being dispatched (single dispatch = array of one) */
|
|
8
|
+
jobs: JobData[];
|
|
9
|
+
/** Target queue name */
|
|
10
|
+
queue: string;
|
|
11
|
+
/** Delay in milliseconds before the job becomes available */
|
|
12
|
+
delay?: number;
|
|
13
|
+
/** Error that caused the dispatch to fail */
|
|
14
|
+
error?: Error;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Tracing data structure for job execution events.
|
|
18
|
+
*/
|
|
19
|
+
type JobExecuteMessage = {
|
|
20
|
+
/** The acquired job being executed */
|
|
21
|
+
job: AcquiredJob;
|
|
22
|
+
/** Queue the job was acquired from */
|
|
23
|
+
queue: string;
|
|
24
|
+
/** Execution outcome (set in asyncEnd) */
|
|
25
|
+
status?: 'completed' | 'failed' | 'retrying';
|
|
26
|
+
/** Execution duration in milliseconds (set in asyncEnd) */
|
|
27
|
+
duration?: number;
|
|
28
|
+
/** Error that caused the failure (set in asyncEnd) */
|
|
29
|
+
error?: Error;
|
|
30
|
+
/** When the next retry is scheduled (set in asyncEnd for retrying jobs) */
|
|
31
|
+
nextRetryAt?: Date;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type { JobDispatchMessage, JobExecuteMessage };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=tracing_channels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@boringnode/queue",
|
|
3
3
|
"description": "A simple and efficient queue system for Node.js applications",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.1",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
],
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./build/index.js",
|
|
12
|
+
"./otel": "./build/src/otel.js",
|
|
12
13
|
"./drivers/*": "./build/src/drivers/*.js",
|
|
13
14
|
"./contracts/*": "./build/src/contracts/*.js",
|
|
14
15
|
"./types": "./build/src/types/index.js"
|
|
@@ -40,29 +41,46 @@
|
|
|
40
41
|
"@japa/expect-type": "^2.0.4",
|
|
41
42
|
"@japa/file-system": "^3.0.0",
|
|
42
43
|
"@japa/runner": "^5.3.0",
|
|
44
|
+
"@opentelemetry/api": "^1.9.0",
|
|
45
|
+
"@opentelemetry/context-async-hooks": "^2.6.0",
|
|
46
|
+
"@opentelemetry/core": "^2.6.0",
|
|
47
|
+
"@opentelemetry/instrumentation": "^0.213.0",
|
|
48
|
+
"@opentelemetry/sdk-trace-base": "^2.6.0",
|
|
43
49
|
"@poppinss/ts-exec": "^1.4.4",
|
|
44
50
|
"@types/better-sqlite3": "^7.6.13",
|
|
45
|
-
"@types/node": "^
|
|
46
|
-
"@types/pg": "^8.
|
|
47
|
-
"better-sqlite3": "^12.
|
|
48
|
-
"bullmq": "^5.
|
|
51
|
+
"@types/node": "^25.5.0",
|
|
52
|
+
"@types/pg": "^8.20.0",
|
|
53
|
+
"better-sqlite3": "^12.8.0",
|
|
54
|
+
"bullmq": "^5.71.0",
|
|
49
55
|
"c8": "^11.0.0",
|
|
50
56
|
"del-cli": "^7.0.0",
|
|
51
|
-
"ioredis": "^5.10.
|
|
52
|
-
"knex": "
|
|
53
|
-
"oxfmt": "^0.
|
|
54
|
-
"oxlint": "^1.
|
|
55
|
-
"oxlint-tsgolint": "^0.
|
|
56
|
-
"pg": "^8.
|
|
57
|
+
"ioredis": "^5.10.1",
|
|
58
|
+
"knex": "3.1.0",
|
|
59
|
+
"oxfmt": "^0.41.0",
|
|
60
|
+
"oxlint": "^1.56.0",
|
|
61
|
+
"oxlint-tsgolint": "^0.17.1",
|
|
62
|
+
"pg": "^8.20.0",
|
|
57
63
|
"release-it": "^19.2.4",
|
|
58
64
|
"tsup": "^8.5.1",
|
|
59
65
|
"typescript": "^5.9.3"
|
|
60
66
|
},
|
|
61
67
|
"peerDependencies": {
|
|
68
|
+
"@opentelemetry/api": "^1.9.0",
|
|
69
|
+
"@opentelemetry/core": "^1.30.0 || ^2.0.0",
|
|
70
|
+
"@opentelemetry/instrumentation": "^0.200.0",
|
|
62
71
|
"ioredis": "^5.0.0",
|
|
63
72
|
"knex": "^3.0.0"
|
|
64
73
|
},
|
|
65
74
|
"peerDependenciesMeta": {
|
|
75
|
+
"@opentelemetry/api": {
|
|
76
|
+
"optional": true
|
|
77
|
+
},
|
|
78
|
+
"@opentelemetry/core": {
|
|
79
|
+
"optional": true
|
|
80
|
+
},
|
|
81
|
+
"@opentelemetry/instrumentation": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
66
84
|
"ioredis": {
|
|
67
85
|
"optional": true
|
|
68
86
|
},
|
|
@@ -89,7 +107,8 @@
|
|
|
89
107
|
],
|
|
90
108
|
"publishConfig": {
|
|
91
109
|
"access": "public",
|
|
92
|
-
"tag": "latest"
|
|
110
|
+
"tag": "latest",
|
|
111
|
+
"provenance": true
|
|
93
112
|
},
|
|
94
113
|
"release-it": {
|
|
95
114
|
"git": {
|
|
@@ -101,6 +120,10 @@
|
|
|
101
120
|
"release": true,
|
|
102
121
|
"releaseName": "v${version}",
|
|
103
122
|
"web": true
|
|
123
|
+
},
|
|
124
|
+
"npm": {
|
|
125
|
+
"publish": true,
|
|
126
|
+
"skipChecks": true
|
|
104
127
|
}
|
|
105
128
|
},
|
|
106
129
|
"packageManager": "yarn@4.12.0",
|