-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
fix(cloudflare): Wait for async events to finish #18334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
packages/cloudflare/src/client.ts
Outdated
| await spanCompletionRace; | ||
| } | ||
|
|
||
| this._resetSpanCompletionPromise(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Race condition clears pending spans during flush
The unconditional call to _resetSpanCompletionPromise() after waiting for pending spans creates a race condition. If new spans start after the await completes but before the reset executes, their tracking state gets cleared. This causes those spans to not be waited for in subsequent flushes and potentially not be sent to Sentry. The reset should only clear the state that was waited for, not any new spans that started concurrently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is actually a very good point. I actually added it for 1 reason, but by then the code looked a little different. The reason was that it could happen that there is some stale data somehow, but this couldn't happen anymore since there is a Promise.race and a conditional before.
Will remove it.
1dbcd6e to
4366338
Compare
4366338 to
3ef53d7
Compare
packages/cloudflare/src/client.ts
Outdated
| } | ||
|
|
||
| this._resetSpanCompletionPromise(); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Timeout budget not properly managed across operations
The timeout parameter represents the total time budget for the entire flush operation, but the implementation uses it twice: first for waiting for pending spans (line 84) and then passes the same value to super.flush(timeout) (line 101). This means the actual total time could be up to double the intended timeout. The remaining time budget should be calculated after the span wait completes and passed to the parent flush method.
Problem
In getsentry/sentry-mcp#652 we had to manually wait for the flush to ensure that async operations completed before the response was sent.
This was caused by the MCP server streaming data after the actual request has been finished. When using the Cloudflare SDK with MCP servers (or other streaming APIs), spans created during the streaming phase were not being flushed properly because the
flush()method would complete before these async spans finished.Solution
During the request, when a span is created for the streaming call, we now register listeners on the CloudflareClient for
spanStartandspanEndevents. The client tracks all pending spans and waits for them to complete before flushing.Specifically:
_pendingSpansSet to track active span IDs_spanCompletionPromise) to wait for all spans to completeflush()method to wait for pending spans before callingsuper.flush()Test
Added a comprehensive E2E test application (
cloudflare-mcp) that:The test confirms that spans are now flushed correctly without manual intervention.