Skip to content

Commit ad7c159

Browse files
committed
ensure initial checkin and terminal checkin have same trace
1 parent b9b6ba7 commit ad7c159

File tree

3 files changed

+50
-67
lines changed

3 files changed

+50
-67
lines changed

dev-packages/node-integration-tests/suites/public-api/withMonitor/scenario.ts

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,36 @@ Sentry.init({
77
transport: loggingTransport,
88
});
99

10-
// eslint-disable-next-line @sentry-internal/sdk/no-floating-promises
11-
Sentry.withMonitor('cron-job-1', async () => {
12-
await new Promise<void>((resolve) => {
13-
setTimeout(() => {
14-
resolve();
15-
}, 100);
16-
});
17-
}, {
18-
schedule: { type: 'crontab', value: '* * * * *' },
19-
});
10+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
11+
Sentry.withMonitor(
12+
'cron-job-1',
13+
async () => {
14+
await new Promise<void>(resolve => {
15+
setTimeout(() => {
16+
resolve();
17+
}, 100);
18+
});
19+
},
20+
{
21+
schedule: { type: 'crontab', value: '* * * * *' },
22+
},
23+
);
2024

21-
// eslint-disable-next-line @sentry-internal/sdk/no-floating-promises
22-
Sentry.withMonitor('cron-job-2', async () => {
23-
await new Promise<void>((resolve) => {
24-
setTimeout(() => {
25-
resolve();
26-
}, 100);
27-
});
28-
}, {
29-
schedule: { type: 'crontab', value: '* * * * *' },
30-
isolateTrace: true,
31-
});
25+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
26+
Sentry.withMonitor(
27+
'cron-job-2',
28+
async () => {
29+
await new Promise<void>(resolve => {
30+
setTimeout(() => {
31+
resolve();
32+
}, 100);
33+
});
34+
},
35+
{
36+
schedule: { type: 'crontab', value: '* * * * *' },
37+
isolateTrace: true,
38+
},
39+
);
3240

3341
setTimeout(() => {
3442
process.exit();

dev-packages/node-integration-tests/suites/public-api/withMonitor/test.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,21 @@ describe('withMonitor isolateTrace', () => {
3434
.start()
3535
.completed();
3636

37-
// Find the two 'ok' check-ins for comparison
37+
const checkIn1InProgress = checkIns.find(c => c.monitor_slug === 'cron-job-1' && c.status === 'in_progress');
3838
const checkIn1Ok = checkIns.find(c => c.monitor_slug === 'cron-job-1' && c.status === 'ok');
39+
40+
const checkIn2InProgress = checkIns.find(c => c.monitor_slug === 'cron-job-2' && c.status === 'in_progress');
3941
const checkIn2Ok = checkIns.find(c => c.monitor_slug === 'cron-job-2' && c.status === 'ok');
4042

41-
expect(checkIn1Ok).toBeDefined();
42-
expect(checkIn2Ok).toBeDefined();
43+
expect(checkIn1InProgress?.contexts?.trace?.trace_id).toMatch(/[a-f\d]{32}/);
44+
expect(checkIn1Ok?.contexts?.trace?.trace_id).toMatch(/[a-f\d]{32}/);
45+
expect(checkIn2InProgress?.contexts?.trace?.trace_id).toMatch(/[a-f\d]{32}/);
46+
expect(checkIn2Ok?.contexts?.trace?.trace_id).toMatch(/[a-f\d]{32}/);
4347

44-
// Verify both check-ins have trace contexts
45-
expect(checkIn1Ok!.contexts?.trace?.trace_id).toBeDefined();
46-
expect(checkIn2Ok!.contexts?.trace?.trace_id).toBeDefined();
48+
expect(checkIn1InProgress!.contexts?.trace?.trace_id).not.toBe(checkIn2InProgress!.contexts?.trace?.trace_id);
49+
expect(checkIn1Ok!.contexts?.trace?.trace_id).toBe(checkIn1InProgress!.contexts?.trace?.trace_id);
4750

48-
// The key assertion: trace IDs should be different when isolateTrace is enabled
49-
expect(checkIn1Ok!.contexts!.trace!.trace_id).not.toBe(checkIn2Ok!.contexts!.trace!.trace_id);
51+
expect(checkIn2InProgress!.contexts?.trace?.trace_id).not.toBe(checkIn1InProgress!.contexts?.trace?.trace_id);
52+
expect(checkIn2Ok!.contexts?.trace?.trace_id).toBe(checkIn2InProgress!.contexts?.trace?.trace_id);
5053
});
51-
});
54+
});

packages/core/src/exports.ts

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { getClient, getCurrentScope, getIsolationScope, withIsolationScope } fro
22
import { DEBUG_BUILD } from './debug-build';
33
import type { CaptureContext } from './scope';
44
import { closeSession, makeSession, updateSession } from './session';
5+
import { startNewTrace } from './tracing/trace';
56
import type { CheckIn, FinishedCheckIn, MonitorConfig } from './types-hoist/checkin';
67
import type { Event, EventHint } from './types-hoist/event';
78
import type { EventProcessor } from './types-hoist/eventprocessor';
@@ -15,7 +16,6 @@ import { isThenable } from './utils/is';
1516
import { uuid4 } from './utils/misc';
1617
import type { ExclusiveEventHintOrCaptureContext } from './utils/prepareEvent';
1718
import { parseEventHintOrCaptureContext } from './utils/prepareEvent';
18-
import { startNewTrace } from './tracing/trace';
1919
import { timestampInSeconds } from './utils/time';
2020
import { GLOBAL_OBJ } from './utils/worldwide';
2121

@@ -160,43 +160,13 @@ export function withMonitor<T>(
160160
callback: () => T,
161161
upsertMonitorConfig?: MonitorConfig,
162162
): T {
163-
const checkInId = captureCheckIn({ monitorSlug, status: 'in_progress' }, upsertMonitorConfig);
164-
const now = timestampInSeconds();
163+
function runCallback(): T {
164+
const checkInId = captureCheckIn({ monitorSlug, status: 'in_progress' }, upsertMonitorConfig);
165+
const now = timestampInSeconds();
165166

166-
function finishCheckIn(status: FinishedCheckIn['status']): void {
167-
captureCheckIn({ monitorSlug, status, checkInId, duration: timestampInSeconds() - now });
168-
}
169-
170-
return withIsolationScope(() => {
171-
// If isolateTrace is enabled, start a new trace for this monitor execution
172-
if (upsertMonitorConfig?.isolateTrace) {
173-
return startNewTrace(() => {
174-
let maybePromiseResult: T;
175-
try {
176-
maybePromiseResult = callback();
177-
} catch (e) {
178-
finishCheckIn('error');
179-
throw e;
180-
}
181-
182-
if (isThenable(maybePromiseResult)) {
183-
return maybePromiseResult.then(
184-
r => {
185-
finishCheckIn('ok');
186-
return r;
187-
},
188-
e => {
189-
finishCheckIn('error');
190-
throw e;
191-
},
192-
) as T;
193-
}
194-
finishCheckIn('ok');
195-
196-
return maybePromiseResult;
197-
});
167+
function finishCheckIn(status: FinishedCheckIn['status']): void {
168+
captureCheckIn({ monitorSlug, status, checkInId, duration: timestampInSeconds() - now });
198169
}
199-
200170
// Default behavior without isolateTrace
201171
let maybePromiseResult: T;
202172
try {
@@ -221,7 +191,9 @@ export function withMonitor<T>(
221191
finishCheckIn('ok');
222192

223193
return maybePromiseResult;
224-
});
194+
}
195+
196+
return withIsolationScope(() => (upsertMonitorConfig?.isolateTrace ? startNewTrace(runCallback) : runCallback()));
225197
}
226198

227199
/**

0 commit comments

Comments
 (0)