Skip to content

Ensure cross-context promise settlements run under an IncomingRequest - #7004

Draft
jqmmes wants to merge 2 commits into
mainfrom
joaquim/fix-io-context-run
Draft

Ensure cross-context promise settlements run under an IncomingRequest#7004
jqmmes wants to merge 2 commits into
mainfrom
joaquim/fix-io-context-run

Conversation

@jqmmes

@jqmmes jqmmes commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Prevent an actor's delete-queue signal task from calling IoContext::run()
without a current IncomingRequest.

Cross-context promise actions now run under a live request. If the actor is
idle, they remain queued until its next real event creates an
IncomingRequest.

Cross-context promise resolution queues actions on the target
IoContext's DeleteQueue. Running an action settles a promise, which can
run application JavaScript, which is in turn free to schedule another
action on the same queue. Holding the queue's lock while running actions
would therefore deadlock.

Add takeActions(), which moves the queued actions out from under the
lock and hands them to the caller to run after it is released. Make
resetCrossThreadSignal() public so the queue's owner can re-arm the
signal independently of draining, and cover both in io-own-test.

Nothing calls takeActions() yet, so this is inert.
@ask-bonk

ask-bonk Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

APIError: Invalid Anthropic API Key

github run

2 similar comments
@ask-bonk

ask-bonk Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

APIError: Invalid Anthropic API Key

github run

@ask-bonk

ask-bonk Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

APIError: Invalid Anthropic API Key

github run

@ask-bonk

ask-bonk Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

@jqmmes Bonk workflow failed. Check the logs for details.

View workflow run · To retry, trigger Bonk again.

The delete queue signal task woke on a queued cross-context promise
settlement and immediately called run() to execute it. run() reaches
IoContext::now() while acquiring the actor's locks, and now() requires a
current IncomingRequest. An actor's IoContext outlives its requests, so a
settlement arriving while the actor sat idle -- holding hibernatable
WebSockets, say -- failed the "the IoContext has no current
IncomingRequest" requirement and aborted the IoContext, breaking every
consumer of that actor.

Settling a promise runs application JavaScript, which needs the metrics,
tracing, timers, and IoChannelFactory that only an IncomingRequest
supplies, so there is no correct way to run one without a request.
Instead:

- runImpl() drains the queue before delivering an event, so actions run
  under a request that is already fully formed.
- The signal task asks scheduleCrossContextActionDrain() for a run, which
  returns none when no request could own one, leaving the actions queued
  for the actor's next event. Otherwise it registers the run as a
  wait-until task so the request cannot drain from under it.
- The signal is re-armed before draining. Consuming a signal without
  installing a fresh one first left an action that arrived mid-drain
  queued with nothing outstanding to wake the context again, so it sat
  there until an unrelated action happened along.

The handle_cross_request_promise_resolution flag guarantees that a
promise settles in its owning IoContext, not that it settles promptly, so
deferring to the next event keeps that contract. A deferred settlement
does wait for the next event to arrive, which is a large improvement over
aborting the actor outright.

Cover settlement under an active request, under a draining request with
waitUntil work outstanding, and on an idle actor where it must wait for
the next event. Also drive the signal task directly, through the executor
a promise's context tag hands out, to cover an action scheduled while a
drain is already in progress.
@jqmmes
jqmmes force-pushed the joaquim/fix-io-context-run branch from d91ae53 to 02ca769 Compare August 14, 2026 09:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant