Skip to content

Commit e8d255f

Browse files
authored
Revert "feat(cloudflare): Introduce lock instrumentation for context.waitUntil to prevent multiple instrumentation (#17539)" (#17666)
This PR reverts #17539 because it causes e2e test fails on PRs as well as on `develop` and release branches. It seems like when our e2e tests expect errors in websocket, another unrelated error is thrown: ``` ✘ 5 [chromium] › tests/index.test.ts:41:5 › Websocket.webSocketMessage (13ms) [WebServer] ✘ [ERROR] Uncaught TypeError: Illegal invocation: function called with incorrect `this` reference. See https://developers.cloudflare.com/workers/observability/errors/#illegal-invocation-errors for details. Error [WebServer] [WebServer] at fetch (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/src/index.ts:32:18) [WebServer] at null.<anonymous> (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+cloudflare@10.11.0_@cloudflare+workers-types@4.20250913.0/node_modules/@sentry/cloudflare/src/durableobject.ts:219:23) [WebServer] at null.<anonymous> (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+cloudflare@10.11.0_@cloudflare+workers-types@4.20250913.0/node_modules/@sentry/cloudflare/src/request.ts:108:33) [WebServer] at handleCallbackErrors.status.status (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+core@10.11.0/node_modules/@sentry/core/src/tracing/trace.ts:77:15) [WebServer] at handleCallbackErrors (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+core@10.11.0/node_modules/@sentry/core/src/utils/handleCallbackErrors.ts:20:26) [WebServer] at null.<anonymous> (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+core@10.11.0/node_modules/@sentry/core/src/tracing/trace.ts:76:14) [WebServer] at null.<anonymous> (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+core@10.11.0/node_modules/@sentry/core/src/tracing/trace.ts:530:100) [WebServer] at null.<anonymous> (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+core@10.11.0/node_modules/@sentry/core/src/tracing/trace.ts:60:12) [WebServer] at null.<anonymous> (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+cloudflare@10.11.0_@cloudflare+workers-types@4.20250913.0/node_modules/@sentry/cloudflare/src/async.ts:41:14) [WebServer] at withScope (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+cloudflare@10.11.0_@cloudflare+workers-types@4.20250913.0/node_modules/@sentry/cloudflare/src/async.ts:40:25) [WebServer] at withScope (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+core@10.11.0/node_modules/@sentry/core/src/currentScopes.ts:59:18) [WebServer] at startSpan (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+core@10.11.0/node_modules/@sentry/core/src/tracing/trace.ts:56:10) [WebServer] at null.<anonymous> (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+cloudflare@10.11.0_@cloudflare+workers-types@4.20250913.0/node_modules/@sentry/cloudflare/src/request.ts:101:16) [WebServer] at null.<anonymous> (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+core@10.11.0/node_modules/@sentry/core/src/tracing/trace.ts:229:12) [WebServer] at null.<anonymous> (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+cloudflare@10.11.0_@cloudflare+workers-types@4.20250913.0/node_modules/@sentry/cloudflare/src/async.ts:41:14) [WebServer] at withScope (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+cloudflare@10.11.0_@cloudflare+workers-types@4.20250913.0/node_modules/@sentry/cloudflare/src/async.ts:40:25) [WebServer] at withScope (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+core@10.11.0/node_modules/@sentry/core/src/currentScopes.ts:65:14) [WebServer] at continueTrace (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+core@10.11.0/node_modules/@sentry/core/src/tracing/trace.ts:226:10) [WebServer] at null.<anonymous> (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+cloudflare@10.11.0_@cloudflare+workers-types@4.20250913.0/node_modules/@sentry/cloudflare/src/request.ts:95:12) [WebServer] at null.<anonymous> (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+cloudflare@10.11.0_@cloudflare+workers-types@4.20250913.0/node_modules/@sentry/cloudflare/src/async.ts:56:14) [WebServer] at withIsolationScope (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+cloudflare@10.11.0_@cloudflare+workers-types@4.20250913.0/node_modules/@sentry/cloudflare/src/async.ts:55:25) [WebServer] at withIsolationScope (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+core@10.11.0/node_modules/@sentry/core/src/currentScopes.ts:114:14) [WebServer] at wrapRequestHandler (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+cloudflare@10.11.0_@cloudflare+workers-types@4.20250913.0/node_modules/@sentry/cloudflare/src/request.ts:43:10) [WebServer] at apply (file:///private/var/folders/63/gxb4ks2n7wbf_7bbwz86cgsc0000gn/T/sentry-e2e-tests-cloudflare-workers-fU9D9e/node_modules/.pnpm/@sentry+cloudflare@10.11.0_@cloudflare+workers-types@4.20250913.0/node_modules/@sentry/cloudflare/src/durableobject.ts:218:20) [WebServer] [WebServer] ``` The SDK catches this error instead but the tests fail because they expect the other error. Not sure what in #17539 caused this but for now let's unblock ourselves first and follow up with a fix in a new attempt (cc @0xbad0c0d3 )
1 parent 57b0656 commit e8d255f

File tree

15 files changed

+162
-302
lines changed

15 files changed

+162
-302
lines changed

dev-packages/e2e-tests/test-applications/cloudflare-workers/tests/index.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ test("Request processed by DurableObject's fetch is recorded", async ({ baseURL
4040

4141
test('Websocket.webSocketMessage', async ({ baseURL }) => {
4242
const eventWaiter = waitForError('cloudflare-workers', event => {
43-
return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object';
43+
return !!event.exception?.values?.[0];
4444
});
4545
const url = new URL('/pass-to-object/ws', baseURL);
4646
url.protocol = url.protocol.replace('http', 'ws');
@@ -51,11 +51,12 @@ test('Websocket.webSocketMessage', async ({ baseURL }) => {
5151
const event = await eventWaiter;
5252
socket.close();
5353
expect(event.exception?.values?.[0]?.value).toBe('Should be recorded in Sentry: webSocketMessage');
54+
expect(event.exception?.values?.[0]?.mechanism?.type).toBe('auto.faas.cloudflare.durable_object');
5455
});
5556

5657
test('Websocket.webSocketClose', async ({ baseURL }) => {
5758
const eventWaiter = waitForError('cloudflare-workers', event => {
58-
return event.exception?.values?.[0]?.mechanism?.type === 'auto.faas.cloudflare.durable_object';
59+
return !!event.exception?.values?.[0];
5960
});
6061
const url = new URL('/pass-to-object/ws', baseURL);
6162
url.protocol = url.protocol.replace('http', 'ws');
@@ -66,4 +67,5 @@ test('Websocket.webSocketClose', async ({ baseURL }) => {
6667
});
6768
const event = await eventWaiter;
6869
expect(event.exception?.values?.[0]?.value).toBe('Should be recorded in Sentry: webSocketClose');
70+
expect(event.exception?.values?.[0]?.mechanism?.type).toBe('auto.faas.cloudflare.durable_object');
6971
});

packages/cloudflare/src/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ClientOptions, Options, ServerRuntimeClientOptions } from '@sentry/core';
22
import { applySdkMetadata, ServerRuntimeClient } from '@sentry/core';
3+
import type { makeFlushLock } from './flush';
34
import type { CloudflareTransportOptions } from './transport';
4-
import type { makeFlushLock } from './utils/flushLock';
55

66
/**
77
* The Sentry Cloudflare SDK Client.

packages/cloudflare/src/durableobject.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import { isInstrumented, markAsInstrumented } from './instrument';
1818
import { getFinalOptions } from './options';
1919
import { wrapRequestHandler } from './request';
2020
import { init } from './sdk';
21-
import { copyExecutionContext } from './utils/copyExecutionContext';
2221

2322
type MethodWrapperOptions = {
2423
spanName?: string;
@@ -193,11 +192,9 @@ export function instrumentDurableObjectWithSentry<
193192
C extends new (state: DurableObjectState, env: E) => T,
194193
>(optionsCallback: (env: E) => CloudflareOptions, DurableObjectClass: C): C {
195194
return new Proxy(DurableObjectClass, {
196-
construct(target, [ctx, env]) {
195+
construct(target, [context, env]) {
197196
setAsyncLocalStorageAsyncContextStrategy();
198197

199-
const context = copyExecutionContext(ctx);
200-
201198
const options = getFinalOptions(optionsCallback(env), env);
202199

203200
const obj = new target(context, env);

packages/cloudflare/src/flush.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import type { ExecutionContext } from '@cloudflare/workers-types';
2+
3+
type FlushLock = {
4+
readonly ready: Promise<void>;
5+
readonly finalize: () => Promise<void>;
6+
};
7+
8+
/**
9+
* Enhances the given execution context by wrapping its `waitUntil` method with a proxy
10+
* to monitor pending tasks, and provides a flusher function to ensure all tasks
11+
* have been completed before executing any subsequent logic.
12+
*
13+
* @param {ExecutionContext} context - The execution context to be enhanced. If no context is provided, the function returns undefined.
14+
* @return {FlushLock} Returns a flusher function if a valid context is provided, otherwise undefined.
15+
*/
16+
export function makeFlushLock(context: ExecutionContext): FlushLock {
17+
let resolveAllDone: () => void = () => undefined;
18+
const allDone = new Promise<void>(res => {
19+
resolveAllDone = res;
20+
});
21+
let pending = 0;
22+
const originalWaitUntil = context.waitUntil.bind(context) as typeof context.waitUntil;
23+
context.waitUntil = promise => {
24+
pending++;
25+
return originalWaitUntil(
26+
promise.finally(() => {
27+
if (--pending === 0) resolveAllDone();
28+
}),
29+
);
30+
};
31+
return Object.freeze({
32+
ready: allDone,
33+
finalize: () => {
34+
if (pending === 0) resolveAllDone();
35+
return allDone;
36+
},
37+
});
38+
}

packages/cloudflare/src/handler.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import { getFinalOptions } from './options';
1414
import { wrapRequestHandler } from './request';
1515
import { addCloudResourceContext } from './scope-utils';
1616
import { init } from './sdk';
17-
import { copyExecutionContext } from './utils/copyExecutionContext';
1817

1918
/**
2019
* Wrapper for Cloudflare handlers.
@@ -38,11 +37,9 @@ export function withSentry<Env = unknown, QueueHandlerMessage = unknown, CfHostM
3837
if ('fetch' in handler && typeof handler.fetch === 'function' && !isInstrumented(handler.fetch)) {
3938
handler.fetch = new Proxy(handler.fetch, {
4039
apply(target, thisArg, args: Parameters<ExportedHandlerFetchHandler<Env, CfHostMetadata>>) {
41-
const [request, env, ctx] = args;
40+
const [request, env, context] = args;
4241

4342
const options = getFinalOptions(optionsCallback(env), env);
44-
const context = copyExecutionContext(ctx);
45-
args[2] = context;
4643

4744
return wrapRequestHandler({ options, request, context }, () => target.apply(thisArg, args));
4845
},
@@ -74,9 +71,7 @@ export function withSentry<Env = unknown, QueueHandlerMessage = unknown, CfHostM
7471
if ('scheduled' in handler && typeof handler.scheduled === 'function' && !isInstrumented(handler.scheduled)) {
7572
handler.scheduled = new Proxy(handler.scheduled, {
7673
apply(target, thisArg, args: Parameters<ExportedHandlerScheduledHandler<Env>>) {
77-
const [event, env, ctx] = args;
78-
const context = copyExecutionContext(ctx);
79-
args[2] = context;
74+
const [event, env, context] = args;
8075
return withIsolationScope(isolationScope => {
8176
const options = getFinalOptions(optionsCallback(env), env);
8277
const waitUntil = context.waitUntil.bind(context);
@@ -119,9 +114,7 @@ export function withSentry<Env = unknown, QueueHandlerMessage = unknown, CfHostM
119114
if ('email' in handler && typeof handler.email === 'function' && !isInstrumented(handler.email)) {
120115
handler.email = new Proxy(handler.email, {
121116
apply(target, thisArg, args: Parameters<EmailExportedHandler<Env>>) {
122-
const [emailMessage, env, ctx] = args;
123-
const context = copyExecutionContext(ctx);
124-
args[2] = context;
117+
const [emailMessage, env, context] = args;
125118
return withIsolationScope(isolationScope => {
126119
const options = getFinalOptions(optionsCallback(env), env);
127120
const waitUntil = context.waitUntil.bind(context);
@@ -162,9 +155,7 @@ export function withSentry<Env = unknown, QueueHandlerMessage = unknown, CfHostM
162155
if ('queue' in handler && typeof handler.queue === 'function' && !isInstrumented(handler.queue)) {
163156
handler.queue = new Proxy(handler.queue, {
164157
apply(target, thisArg, args: Parameters<ExportedHandlerQueueHandler<Env, QueueHandlerMessage>>) {
165-
const [batch, env, ctx] = args;
166-
const context = copyExecutionContext(ctx);
167-
args[2] = context;
158+
const [batch, env, context] = args;
168159

169160
return withIsolationScope(isolationScope => {
170161
const options = getFinalOptions(optionsCallback(env), env);
@@ -214,9 +205,7 @@ export function withSentry<Env = unknown, QueueHandlerMessage = unknown, CfHostM
214205
if ('tail' in handler && typeof handler.tail === 'function' && !isInstrumented(handler.tail)) {
215206
handler.tail = new Proxy(handler.tail, {
216207
apply(target, thisArg, args: Parameters<ExportedHandlerTailHandler<Env>>) {
217-
const [, env, ctx] = args;
218-
const context = copyExecutionContext(ctx);
219-
args[2] = context;
208+
const [, env, context] = args;
220209

221210
return withIsolationScope(async isolationScope => {
222211
const options = getFinalOptions(optionsCallback(env), env);

packages/cloudflare/src/sdk.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ import {
1212
} from '@sentry/core';
1313
import type { CloudflareClientOptions, CloudflareOptions } from './client';
1414
import { CloudflareClient } from './client';
15+
import { makeFlushLock } from './flush';
1516
import { fetchIntegration } from './integrations/fetch';
1617
import { setupOpenTelemetryTracer } from './opentelemetry/tracer';
1718
import { makeCloudflareTransport } from './transport';
18-
import { makeFlushLock } from './utils/flushLock';
1919
import { defaultStackParser } from './vendor/stacktrace';
2020

2121
/** Get the default integrations for the Cloudflare SDK. */

packages/cloudflare/src/utils/copyExecutionContext.ts

Lines changed: 0 additions & 47 deletions
This file was deleted.

packages/cloudflare/src/utils/flushLock.ts

Lines changed: 0 additions & 57 deletions
This file was deleted.

packages/cloudflare/src/utils/makePromiseResolver.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

packages/cloudflare/test/copy-execution-context.test.ts

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)