Skip to content

Support for DO shutdown hooks - #7041

Open
a-robinson wants to merge 3 commits into
mainfrom
arobinson/do-pre-shutdown
Open

Support for DO shutdown hooks#7041
a-robinson wants to merge 3 commits into
mainfrom
arobinson/do-pre-shutdown

Conversation

@a-robinson

Copy link
Copy Markdown
Member

No description provided.

Comment thread src/workerd/api/actor.h Outdated
// preShutdown is reserved by the Durable Objects implementation, but only when the target
// worker has opted in via the compatibility flag, since existing classes may already export
// an RPC method with this name.
if (name == "preShutdown" && FeatureFlags::get(js).getDurableObjectPreShutdown()) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switch to [shutdown] and remove this reserved name logic/tests?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then the compatibility date can be ripped out too.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still being discussed internally

Comment thread src/workerd/api/global-scope.h Outdated
Comment thread src/workerd/io/worker.c++ Outdated
Comment thread src/workerd/io/worker.c++ Outdated
@a-robinson
a-robinson force-pushed the arobinson/do-pre-shutdown branch from 466e0b0 to 8219cf3 Compare August 18, 2026 03:52
Comment thread src/workerd/io/worker.h
Comment thread src/workerd/io/observer.h Outdated
Comment thread src/workerd/api/global-scope.c++ Outdated
// Unlike the alarm timeout, we do NOT abort the IoContext: teardown is already committed
// and proceeding, and the caller still drains storage writes the handler managed to issue.
// We just stop waiting for the handler. The abandoned handler continuation may keep
// running until that final storage drain completes, after which all of its pending

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the abandoned continuation schedules more storage operations? Can that be prevented?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the usage of onNoPendingFlush in the relevant implementation, those later storage operations are not waited on.

Which is good in the sense that it prevents shutdown from being delayed, but does it cause problems for being able to immediately reuse the on-disk sqlite instance if some in-flight writes to it may get aborted? It's not clear how big of an issue this is in practice.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not fully preventable without aborting the IoContext at timeout, which we deliberately don't do so the drain can run.

Writes issued after onNoPendingFlush aren't waited on, but they were never confirmed to anyone (the output gate never released them), so no observer can have depended on them; teardown aborts them atomically at the storage layer. The SRS on-disk-reuse question is one to handle in edgeworker.

Comment thread src/workerd/io/incoming-request-test.c++ Outdated
Comment thread src/workerd/io/io-context.c++ Outdated
Comment thread src/workerd/io/worker.c++ Outdated
Comment thread src/workerd/server/server.c++ Outdated
Comment thread src/workerd/server/server.c++ Outdated
Comment thread src/workerd/server/server.c++ Outdated
Comment thread src/workerd/server/server.c++ Outdated
Comment thread src/workerd/server/server.c++ Outdated
@a-robinson a-robinson changed the title DRAFT: support for DO shutdown hooks Support for DO shutdown hooks Aug 25, 2026
@a-robinson
a-robinson marked this pull request as ready for review August 25, 2026 16:05
@a-robinson
a-robinson requested review from a team as code owners August 25, 2026 16:05
@a-robinson
a-robinson requested review from jqmmes and penalosa August 25, 2026 16:05
Adds the API surface for the preShutdown() lifecycle hook on
Durable Object classes, gated by the new experimental
durable_object_pre_shutdown compatibility flag. The hook is
invoked on a best-effort basis before planned, storage-healthy
shutdowns. The reason list is extensible so further planned reasons
(such as code-update resets or system-initiated shutdowns) can be
delivered later without another flag.

The actual implementation of the functionality is in the following
commits.
Adds the machinery that actually invokes the preShutdown() Durable
Object lifecycle hook, and wires it into workerd's graceful
eviction paths for local-dev parity.

This is modeled after runAlarm. Some notes on the decisions made:
* If the wall-clock budget is exceeded, we don't abort the IoContext, so
  that writes issued by the handler can still succeed.
* There is no per-request AsyncLocalStorage.
* Exceptions don't propagate anywhere other than invocation logs.
* This code path takes pains to avoid Worker::Actor::addRef() to avoid
  creating a RequestTracker and marking the DO as active.
* After the handler completes, we wait on all storage writes to flush.
* In the case where there were other callbacks active in the DO,
  they're allowed to run up until the point when the handler completes
  but not any more after that point.
* This complicated the DO inactivty shutdown code in server.c++ a bit
  since now there are more possible race conditions there (sorry!).
Adds ActorObserver::preShutdownFinished(), called from
Worker::Actor::runPreShutdownImpl() with the outcome of every hook
run, including the early-exit case where the IoContext is already
gone. Shutdowns that skip the hook synchronously (no applicable
handler) are deliberately not reported, so observers only see actors
that participate in the hook.

The default implementation is a no-op; embedders override it to
count outcomes.
@a-robinson
a-robinson force-pushed the arobinson/do-pre-shutdown branch from 01f27fa to 111d0d3 Compare August 25, 2026 17:53
@a-robinson

Copy link
Copy Markdown
Member Author

Squashed the commits down for easier review. This now LGTM and is ready for review, with the only real caveat being the naming question (preShutdown vs [shutdown]). I suspect we're going to end up going with [shutdown], which means this will need some slight changes, but nothing that should be too hard.

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.

2 participants