Skip to content

Proposal: Allow waitUntil to accept a function returning a Promise for better instrumentation support #6055

@JPeer264

Description

@JPeer264

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:

Image
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):

  1. Intercept the waitUntil call
  2. Establish the proper tracing context (create/activate a span)
  3. Invoke the function within that context
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status

    Untriaged

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions