Skip to content

STOR-5615: Move the Durable Object retry policy to the namespace - #7672

Open
apeacock1991 wants to merge 1 commit into
mainfrom
apeacock/STOR-5615-do-retry-policy-owner
Open

apeacock1991 wants to merge 1 commit into
mainfrom
apeacock/STOR-5615-do-retry-policy-owner

Conversation

@apeacock1991

Copy link
Copy Markdown
Contributor

The retry policy from #7383 now belongs to the Durable Object namespace, not to each binding.

With the policy on DurableObjectNamespaceDesignator, every binding carried its own limits. ctx.exports namespaces have no binding config, so they always passed kj::none. A Worker could set a policy on env.MY_DO and still get the defaults through ctx.exports.MyDO, for the same object.

The Worker that exports a Durable Object should decide how hard calls to it retry, not each caller. So retryPolicy moves to Worker.DurableObjectNamespace:

durableObjectNamespaces = [
  ( className = "Counter", uniqueKey = "counter", retryPolicy = (maxAttempts = 2, timeoutMs = 5000) ),
],

Server::Durable stores it, and every namespace built from that config uses it:

  • env bindings in the owning Worker
  • bindings from other services through serviceName, which already resolve to the owner's Durable
  • ctx.exports

Callers can't pick their own limits any more. The limit checks moved with the field and now name the namespace in the error. A retry policy on an ephemeralLocal namespace is a config error.

The binding field shipped in v1.20260925.2, but nothing sets it. The Miniflare change that would (cloudflare/workers-sdk#15872) hasn't merged and is being reworked to send the policy per class. Cap'n Proto won't let us drop the ordinal, so the field is now obsolete2 @2 :AnyPointer and the runtime ignores it.

Edgeworker needs no change. It reads the policy from each actor namespace global, and its control plane will fill those in from the namespace.

#7383 put retryPolicy on DurableObjectNamespaceDesignator, so each
binding carried its own policy. ctx.exports namespaces have no
binding config and always passed kj::none, so calls through
ctx.exports.MyDO used the defaults even when env.MY_DO did not.

The policy belongs to the Worker that exports the Durable Object, not
to whoever calls it. retryPolicy now lives on
Worker.DurableObjectNamespace and is stored in Server::Durable. Every
namespace built from that config uses it: env bindings in the owning
Worker, bindings from other services through serviceName, and
ctx.exports. Callers can no longer choose their own limits.

The limit checks move with it and now report the namespace instead of
the binding. An ephemeralLocal namespace with a retry policy is a
config error, since ephemeral namespaces never retry through it.

The binding field shipped in v1.20260925.2, but nothing sets it yet;
the Miniflare change that would has not merged. Cap'n Proto needs the
ordinal kept, so it becomes obsolete2 and the runtime ignores it.
@apeacock1991
apeacock1991 requested review from a team as code owners October 9, 2026 10:46
@ask-bonk

ask-bonk Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Review: 2 findings (1 blocking, 1 warning).

Moves Durable Object retry policy configuration from bindings to namespaces and routes it through bindings and ctx.exports.


Reviewed commit: 54a66cab · github run

Comment thread src/workerd/server/workerd.capnp
.enableSql = ns.getEnableSql(),
.containerOptions = ns.hasContainer() ? kj::Maybe(ns.getContainer()) : kj::none});
.containerOptions = ns.hasContainer() ? kj::Maybe(ns.getContainer()) : kj::none,
.retryPolicy = readRetryPolicy(name, ns)});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[WARNING] The new tests cover only rejected configuration. They never enable durable-object-retries-userland and invoke a namespace with a valid policy, so dropping either this assignment or the analogous ctx.exports assignment at line 6202 would still pass. Add a server-level retry test using a failing actor and maxAttempts = 0 or 1, and exercise both the binding and ctx.exports namespace paths.

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