fix(cloudflare): Missing events inside waitUntil #18486
Draft
+229
−66
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.
follow up to #16681
Problem
The waitUntil could take longer than the actual request is taking, which is actually a good thing and wanted by Cloudflare. By definition of our implementation we are ending the root span at the end of the request, while the promise inside waitUntil could still generate events. These events are only send while the root span is still active ("Event 1" in the mermaid diagram), but are not send anymore when the root span ended ("Event 2") and are basically dropped.
sequenceDiagram participant R as Request participant W as waitUntil participant S as Sentry Spans Note over R: Request starts activate R R->>S: Root span starts activate S Note over R,W: User calls ctx.waitUntil(promise) R->>W: Promise created activate W W->>S: Event 1 ✓ Note over S: Captured (span still active) Note over R: Request handler returns deactivate R R->>S: Root span ends deactivate S Note over W: waitUntil continues running... W->>S: Event 2 ✗ Note over S: LOST!<br/>Span already ended W->>W: waitUntil completes deactivate WSolution
There is a way to end the root span after everything has been finished, which allows us to send everything in one transaction. In order to still have a correct span for the request itself, I had to create a dedicated span just for the request (that can be seen in the "after" picture beneath).
Right now we only send one transaction after everything is finished, which could take up to "request time" + 30 seconds (that is the maximum wait time for a
waitUntil). Which means Sentry gets that data after that time. Very soon there will be the concept of span streaming which would make these events available earlier.sequenceDiagram participant R as Request participant W as waitUntil participant S as Root Span Note over R: Request starts activate R R->>S: Root span starts activate S Note over R,W: User calls ctx.waitUntil(promise) R->>W: Promise created activate W W->>S: Event 1 ✓ Note over R: Request handler returns deactivate R Note over S: Root span stays open!<br/>Waiting for waitUntil... Note over W: waitUntil continues running... W->>S: Event 2 ✓ Note over S: Captured!<br/>Same transaction W->>W: waitUntil completes deactivate W R->>S: Root span ends (after all waitUntil done) deactivate SSpecial eyes
There is now an extra span for the
fetch, which is basically the request itself. So this can be looked at with a critical eyeComparison
before:
after: