Problem
FWIW there is no instrumentation just yet natively from Cloudflare for waitUntil
The current waitUntil(promise: Promise<any>) signature makes it difficult to properly instrument background work with OpenTelemetry.
When passing a promise to waitUntil, the async context is captured at promise creation time:
// Async context is already captured when the IIFE is invoked
ctx.waitUntil(doBackgroundWork());
When instrumenting code (especially waitUntil) for observability it could create a problem. By the time waitUntil is being instrumented, the promise already exists with its context "baked in". Child spans created inside the async function end up with the wrong parent.
Following shows a waitUntil function that starts another span right inside. Instead of having the "Subroutine" as children directly of waitUntil it uses http.server instead:
Pseudo code
waitUntil(
(async () => {
// do something
otel.startSpan((span) => {
span.name = 'Subroutine';
// this span's parent is not `waitUntil`, but the `fetch` method
});
})()
)
Proposal
Add an overload that accepts a function returning a Promise:
interface ExecutionContext {
waitUntil(promise: Promise<any>): void; // existing
waitUntil(fn: () => Promise<any>): void; // new
}
Usage:
ctx.waitUntil(doBackgroundWork);
// or
ctx.waitUntil(async () => {
await doBackgroundWork();
// do more
});
This would allow instrumentation wrappers to (and also Cloudflare in their native observability):
- Intercept the
waitUntil call
- Establish the proper tracing context (create/activate a span)
- Invoke the function within that context
- All child spans would correctly inherit the
waitUntil span as parent
Existing code using waitUntil(promise) continues to work unchanged. However, it would still be nice to only have one way in general and maybe move towards the new model.
Problem
The current
waitUntil(promise: Promise<any>)signature makes it difficult to properly instrument background work with OpenTelemetry.When passing a promise to
waitUntil, the async context is captured at promise creation time:When instrumenting code (especially
waitUntil) for observability it could create a problem. By the timewaitUntilis being instrumented, the promise already exists with its context "baked in". Child spans created inside the async function end up with the wrong parent.Following shows a
waitUntilfunction that starts another span right inside. Instead of having the "Subroutine" as children directly ofwaitUntilit useshttp.serverinstead:Pseudo code
Proposal
Add an overload that accepts a function returning a Promise:
Usage:
This would allow instrumentation wrappers to (and also Cloudflare in their native observability):
waitUntilcallwaitUntilspan as parentExisting code using
waitUntil(promise)continues to work unchanged. However, it would still be nice to only have one way in general and maybe move towards the new model.