cloudflare / cloudflare/workerd

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

Open
#6,055 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
8.7k
Forks
739
Avg merge
2d 20h
Merged PRs (30d)
174

Description

### Problem

> FWIW there is no instrumentation just yet natively from Cloudflare for `waitUntil`

The current `waitUntil(promise: Promise)` 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:

```typescript
// 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

```js
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:

```typescript
interface ExecutionContext {
waitUntil(promise: Promise): void; // existing
waitUntil(fn: () => Promise): void; // new
}
```

**Usage:**

```typescript
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.

Contributor guide

Open the contributing guide

Research direction

Start at the ExecutionContext.waitUntil API and trace how its current Promise argument is handled. Compare the proposed function-returning-Promise form with the existing form, then identify the relevant runtime and type coverage needed to verify both remain supported and that instrumentation can establish the intended parent context.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend-api-design
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.