Repository navigation
Conversation
JPeer264
self-requested a review
October 15, 2026 08:47
`withMonitor`, `withIsolationScope`, `trpcMiddleware` and `wrapMcpServerWithSentry` fork the isolation scope. `Scope.clone()` did not copy the invocation state, because it was a symbol property on the scope. Inside the fork, the cached client treated each envelope as sent outside any invocation: it drained the transport at once and could not register the send with `waitUntil`. The runtime cancelled the send when the event ended, so the closing check-in of `withMonitor` was lost when it ended a scheduled, fetch or queue handler. The eager drain also started envelopes that concurrent invocations had queued for their own flush. The state now lives in the scope's `refs`, which `clone()` copies by reference, so a fork shares the state of its invocation.
…vocation The transport holds every envelope until it is drained. Before, a check-in captured inside `withMonitor` was drained at once, because the forked scope had lost the invocation state. Now that the fork keeps the state, the `in_progress` check-in waited for the flush at the end of the invocation. For a callback that runs longer than the check-in margin, Sentry then marked the run as missed. `CloudflareClient.captureCheckIn` now drains the transport after each check-in and registers the drain with the `waitUntil` of the invocation. This replaces the drain that the scheduled handler ran only for the check-ins of Cron Triggers, so `withMonitor` and `captureCheckIn` get the same delivery.
…ous request error `IsolatedPromiseBuffer.drain()` starts the queued requests in a loop. A request that throws synchronously, such as a custom `fetch` that throws, stopped the loop. The drain then threw into its caller, and the requests after it were lost. `CloudflareClient.captureCheckIn` now drains the transport. So such a `fetch` made `withMonitor` throw from its opening check-in, and the callback never ran. The drain now turns a synchronous throw into a rejected request and starts the other requests.
JPeer264
force-pushed
the
fix/cloudflare-withmonitor-waituntil
branch
from
October 15, 2026 09:11
5752281 to
8fd1b5b
Compare
JPeer264
reviewed
Oct 15, 2026
JPeer264
left a comment
Member
There was a problem hiding this comment.
If it is possible to undo the symbol change then it'd be great. LGTM on the rest. Thanks a lot for creating the PR
| * An `in_progress` check-in of a run that is longer than the check-in margin would otherwise | ||
| * reach Sentry too late, and Sentry would mark the run as missed. | ||
| */ | ||
| public override captureCheckIn(checkIn: CheckIn, monitorConfig?: MonitorConfig, scope?: Scope): string { |
Member
There was a problem hiding this comment.
I like that this is now part of the client. Way cleaner than before tbh.
| } | ||
|
|
||
| const INVOCATION_STATE: unique symbol = Symbol('sentryInvocationState'); | ||
| const SCOPE_INVOCATION_FIELD = 'invocationState'; |
Member
There was a problem hiding this comment.
I'm not a big fan of removing the symbol tbh. We could actually leave the symbol as it was before and put it onto the .refs as you did now on line 81.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Before
A local ingest answers after 10 ms. It logs
CANCELLEDwhen the Worker closes the request first.Problem
withMonitorandwithIsolationScopefork the isolation scope. The fork loses the invocation state.waitUntil. The runtime cancels the send when the handler returns.withMonitornever arrives, and Sentry marks every run as timed out.After
The fork keeps the invocation state. Each check-in leaves at once, inside
waitUntil.The same Worker:
10 scenarios, 5 runs each, in
scheduled,fetch,queue, a Durable Object and a Workflow step:developFixes #25373
yarn lint) & (yarn test).Cause, design and tests
Cause.
setInvocationState(utils/invocationContext.ts) stored the state under a symbol key.Scope.clonedoes not copy that key. In a fork,getInvocationStatereturnedundefined, so_setupEagerEnvelopeDelivery(client.ts) sent the envelope at once withoutwaitUntil.trpcMiddlewareandwrapMcpServerWithSentryfork the scope too.Design.
scope.refs, like the active span inspanOnScope.ts. A fork inside an invocation runs in that invocation, so it shares the state.refschange, thein_progresscheck-in waits for the flush at the end of the invocation. A run longer than the check-in margin then shows as missed. SocaptureCheckInsends each check-in at once. The Cron Triggers check-in used its own drain for this before. Now all check-ins use one path, also withcacheClient: false.waitUntilof the invocation with the check-in, so none is lost: 140 of 140 envelopes arrived in 20 overlapping rounds (develop: 120 of 140).IsolatedPromiseBuffer.drain()now turns a synchronous throw of a request into a rejected request. Before, the throw stopped the drain and dropped the other requests.Tests.
instrumentScheduled.test.ts: a 5 minutewithMonitorcallback sendsin_progressbefore it ends. It fails ondevelop.client.test.ts:captureCheckIndrains insidewaitUntil, withcacheClienttrue and false, and does not throw whenfetchthrows.transport.test.ts: a drain continues after a request throws.invocationContext.test.ts: a forked isolation scope returns the same state.yarn testinpackages/cloudflare(1081 tests),yarn lint,yarn lint:typesandyarn build:typespass. The outputs above come fromwrangler dev4.151.0.AI disclosure: AI models helped us find this issue, write the change, and review it.