Skip to content

Commit 891b67d

Browse files
committed
more breadcrumb tests for worker events
1 parent 8ddee17 commit 891b67d

2 files changed

Lines changed: 125 additions & 3 deletions

File tree

dev-packages/e2e-tests/test-applications/nestjs-bullmq/src/jobs/test.processor.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ export class TestProcessor extends WorkerHost {
1717
return { processed: true };
1818
}
1919

20+
if (job.name === 'lifecycle-failed-breadcrumb-test') {
21+
throw new Error('Intentional error to trigger failed event');
22+
}
23+
24+
if (job.name === 'lifecycle-progress-breadcrumb-test') {
25+
await job.updateProgress(50);
26+
return { processed: true };
27+
}
28+
2029
return { processed: true };
2130
}
2231

@@ -29,4 +38,34 @@ export class TestProcessor extends WorkerHost {
2938
});
3039
}
3140
}
41+
42+
@OnWorkerEvent('active')
43+
onActive(job: Job) {
44+
if (job.name === 'lifecycle-active-breadcrumb-test') {
45+
Sentry.addBreadcrumb({
46+
message: 'leaked-breadcrumb-from-active-event',
47+
level: 'info',
48+
});
49+
}
50+
}
51+
52+
@OnWorkerEvent('failed')
53+
onFailed(job: Job) {
54+
if (job.name === 'lifecycle-failed-breadcrumb-test') {
55+
Sentry.addBreadcrumb({
56+
message: 'leaked-breadcrumb-from-failed-event',
57+
level: 'info',
58+
});
59+
}
60+
}
61+
62+
@OnWorkerEvent('progress')
63+
onProgress(job: Job) {
64+
if (job.name === 'lifecycle-progress-breadcrumb-test') {
65+
Sentry.addBreadcrumb({
66+
message: 'leaked-breadcrumb-from-progress-event',
67+
level: 'info',
68+
});
69+
}
70+
}
3271
}

dev-packages/e2e-tests/test-applications/nestjs-bullmq/tests/bullmq.test.ts

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,10 @@ test('BullMQ processor breadcrumbs do not leak into subsequent HTTP requests', a
6161
expect(leakedBreadcrumb).toBeUndefined();
6262
});
6363

64-
// TODO: @OnWorkerEvent handlers run outside the isolation scope created by process().
64+
// TODO: @OnWorkerEvent('completed') handlers run outside the isolation scope created by process().
6565
// They are registered via worker.on() (EventEmitter), so breadcrumbs/tags set there
6666
// leak into the default isolation scope and appear on subsequent HTTP requests.
67-
// This should be fixed in a follow-up by also wrapping lifecycle event handlers.
68-
test('BullMQ @OnWorkerEvent lifecycle breadcrumbs currently leak into subsequent HTTP requests', async ({
67+
test('BullMQ @OnWorkerEvent completed lifecycle breadcrumbs currently leak into subsequent HTTP requests', async ({
6968
baseURL,
7069
}) => {
7170
const processTransactionPromise = waitForTransaction('nestjs-bullmq', transactionEvent => {
@@ -91,3 +90,87 @@ test('BullMQ @OnWorkerEvent lifecycle breadcrumbs currently leak into subsequent
9190
// This SHOULD be toBeUndefined() once lifecycle event isolation is implemented.
9291
expect(leakedBreadcrumb).toBeDefined();
9392
});
93+
94+
// TODO: @OnWorkerEvent('active') handlers run outside the isolation scope created by process().
95+
// Breadcrumbs set there leak into the default isolation scope and appear on subsequent HTTP requests.
96+
test('BullMQ @OnWorkerEvent active lifecycle breadcrumbs currently leak into subsequent HTTP requests', async ({
97+
baseURL,
98+
}) => {
99+
const processTransactionPromise = waitForTransaction('nestjs-bullmq', transactionEvent => {
100+
return transactionEvent.contexts?.trace?.op === 'queue.process';
101+
});
102+
103+
await fetch(`${baseURL}/enqueue/lifecycle-active-breadcrumb-test`);
104+
105+
await processTransactionPromise;
106+
107+
const transactionPromise = waitForTransaction('nestjs-bullmq', transactionEvent => {
108+
return transactionEvent.transaction === 'GET /check-isolation';
109+
});
110+
111+
await fetch(`${baseURL}/check-isolation`);
112+
113+
const transaction = await transactionPromise;
114+
115+
const leakedBreadcrumb = (transaction.breadcrumbs || []).find(
116+
(b: any) => b.message === 'leaked-breadcrumb-from-active-event',
117+
);
118+
// This SHOULD be toBeUndefined() once lifecycle event isolation is implemented.
119+
expect(leakedBreadcrumb).toBeDefined();
120+
});
121+
122+
// TODO: @OnWorkerEvent('failed') handlers run outside the isolation scope created by process().
123+
// Breadcrumbs set there leak into the default isolation scope and appear on subsequent HTTP requests.
124+
test('BullMQ @OnWorkerEvent failed lifecycle breadcrumbs currently leak into subsequent HTTP requests', async ({
125+
baseURL,
126+
}) => {
127+
const processTransactionPromise = waitForTransaction('nestjs-bullmq', transactionEvent => {
128+
return transactionEvent.contexts?.trace?.op === 'queue.process';
129+
});
130+
131+
await fetch(`${baseURL}/enqueue/lifecycle-failed-breadcrumb-test`);
132+
133+
await processTransactionPromise;
134+
135+
const transactionPromise = waitForTransaction('nestjs-bullmq', transactionEvent => {
136+
return transactionEvent.transaction === 'GET /check-isolation';
137+
});
138+
139+
await fetch(`${baseURL}/check-isolation`);
140+
141+
const transaction = await transactionPromise;
142+
143+
const leakedBreadcrumb = (transaction.breadcrumbs || []).find(
144+
(b: any) => b.message === 'leaked-breadcrumb-from-failed-event',
145+
);
146+
// This SHOULD be toBeUndefined() once lifecycle event isolation is implemented.
147+
expect(leakedBreadcrumb).toBeDefined();
148+
});
149+
150+
// The 'progress' event does NOT leak breadcrumbs — unlike 'active', 'completed', and 'failed',
151+
// BullMQ emits it inside the process() call (via job.updateProgress()), so it runs within
152+
// the isolation scope already established by the instrumentation.
153+
test('BullMQ @OnWorkerEvent progress lifecycle breadcrumbs do not leak into subsequent HTTP requests', async ({
154+
baseURL,
155+
}) => {
156+
const processTransactionPromise = waitForTransaction('nestjs-bullmq', transactionEvent => {
157+
return transactionEvent.contexts?.trace?.op === 'queue.process';
158+
});
159+
160+
await fetch(`${baseURL}/enqueue/lifecycle-progress-breadcrumb-test`);
161+
162+
await processTransactionPromise;
163+
164+
const transactionPromise = waitForTransaction('nestjs-bullmq', transactionEvent => {
165+
return transactionEvent.transaction === 'GET /check-isolation';
166+
});
167+
168+
await fetch(`${baseURL}/check-isolation`);
169+
170+
const transaction = await transactionPromise;
171+
172+
const leakedBreadcrumb = (transaction.breadcrumbs || []).find(
173+
(b: any) => b.message === 'leaked-breadcrumb-from-progress-event',
174+
);
175+
expect(leakedBreadcrumb).toBeUndefined();
176+
});

0 commit comments

Comments
 (0)