Repository navigation
[wrangler,miniflare,vite-plugin] Add Durable Object retry policies - #15872
apeacock1991 wants to merge 3 commits into
Conversation
|
I'm Bonk, and I've done a quick review of your PR. Adds Durable Object retry policies and Worker decorator lowering.
|
🦋 Changeset detectedLatest commit: dff1555 The changes in this PR will be included in the next version bump. This PR includes changesets to release 15 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
b0ee729 to
bf0aba3
Compare
@cloudflare/autoconfig
@cloudflare/build-output-utils
@cloudflare/codemods
@cloudflare/config
@cloudflare/containers-shared
create-cloudflare
@cloudflare/deploy-helpers
@cloudflare/kv-asset-handler
miniflare
@cloudflare/pages-functions
@cloudflare/pages-shared
@cloudflare/runtime-types
@cloudflare/unenv-preset
@cloudflare/vite-plugin
@cloudflare/vitest-plugin
@cloudflare/workers-auth
@cloudflare/workers-editor-shared
@cloudflare/workers-utils
wrangler
commit: |
bf0aba3 to
284c689
Compare
|
Codeowners approval required for this PR:
Show detailed file reviewers
|
284c689 to
f5911a0
Compare
jamesopstad
left a comment
There was a problem hiding this comment.
Adding a blocking review until this has been discussed more. I don't we should be adding decorators support to the Vite plugin. There are good reasons that they are not supported in Oxc and they were recently moved back to Stage 2.7.
Additionally, v2 of the Vite plugin (currently in beta) doesn't have a dependency on Wrangler so ESBuild would be a new dependency.
Do you have any suggested alternatives that are also nice from a DX perspective? e.g. this needs to live in the code, on the method it relates to. I went through a lot of options and this came out as the best one, it's also already used in Cap'n stuff I believe so there is precedence for it. For this to work, the runtime needs to know at construction what methods are retryable and what are not, in terms of requirements. |
f5911a0 to
f6ac70f
Compare
|
Codeowners approval required for this PR:
Show detailed file reviewers
|
f884c64 to
011b510
Compare
|
For completeness: after a lengthy discussion, the decision was made to use a directive ("use retry") rather than a decorator, as the latter needed explicit changes to the bundler to make it supported. |
011b510 to
5731b1b
Compare
5731b1b to
70d863c
Compare
70d863c to
d87708b
Compare
d87708b to
b73cacf
Compare
The Worker that exports a Durable Object class owns its retry policy.
Live `exports` entries accept an optional `retry` object, and Workers
that use `migrations` can set it on a binding to a class in the same
Worker. `max_attempts` is the number of retries after the first request,
from 0 to 10. `timeout_ms` is the retry timeout, from 500 to 60,000.
Unknown keys are errors, the same as in the Workers API.
Validation rejects `retry` on a binding with `script_name`, on any
binding in a Worker that declares Durable Objects in `exports`, and on
two bindings to one class with different values. The policy applies to
every caller, so a caller cannot set its own.
Wrangler sends the policy as written with the export or binding in
deploy, versions upload and preview metadata, and reads binding
policies back when it downloads remote config. It never fills in
defaults. The runtime owns those.
The experimental config API accepts `retry: { maxAttempts, timeoutMs }`
on live `durable-object` exports and converts it to Wrangler's shape.
Bindings there have no `retry`.
workerd now reads the retry policy from the Durable Object namespace instead of each binding, so `env`, `ctx.exports` and bindings from other Workers all use the class owner's policy. Miniflare carries `retry` on live durable-object exports and writes it to `DurableObjectNamespace.retryPolicy`. Ephemeral namespaces get no policy, because workerd does not support one there. Miniflare's `durableObjects` and `additionalUnboundDurableObjects` entries accept `retryMaxAttempts` and `retryTimeoutMs`. They configure the class, so an entry with `scriptName` cannot set them, and entries for one class with different values are an error. Wrangler dev builds a class-name-to-policy map from exports and same-Worker bindings and applies it to every local entry for the class. The generated Cap'n Proto types come from the workerd change that moves the policy. The binding field becomes an unused placeholder. Regenerate them when the workerd version is bumped.
Durable Object methods are marked as safe to retry with `retryable()` from the `cloudflare:durable-objects` runtime module. Add it to the plugin's built-in module list so Vite leaves the import for workerd instead of resolving it as a package. Wrangler already treats every `cloudflare:*` import as external.
b73cacf to
dff1555
Compare
This is the workers-sdk side of Durable Object retry controls. The Worker that exports a Durable Object class sets its retry policy, and the runtime applies it however the class is reached:
env,ctx.exports, or a binding from another Worker. Callers can't override it.{ "exports": { "Counter": { "type": "durable-object", "storage": "sqlite", "retry": { "max_attempts": 5, "timeout_ms": 10000 }, }, }, }max_attemptscounts retries after the first request, so 5 allows six attempts in total. Zero turns retries off.timeout_msis a retry timeout, not a request timeout. The first request always runs to completion, and no retry starts once the timeout has passed. Anything omitted uses the runtime defaults of 4 retries and 10,000 ms. Neither setting makes a call retryable if the runtime wouldn't already retry it.Workers still on
migrationscan't useexports, so they can setretryon a binding to a class in the same Worker. That's Wrangler config only.cloudflare.config.tshas it on exports and nowhere else. Validation rejects:retryon a binding withscript_nameretryon both a binding and the class's exportA method opts into retries that may run it twice with
retryable()from thecloudflare:durable-objectsruntime module. The runtime side is cloudflare/workerd#7617, and moving the policy onto the namespace is a separate workerd PR.It's easiest to review one commit at a time.
retryon live exports in the experimental config API. Exports already upload as written, soexports.<Class>.retrygoes out as{ max_attempts, timeout_ms }. Same-Worker bindings keep sendingretryin the same shape. Wrangler never fills in defaults.DurableObjectNamespace.retryPolicyrather than to each binding. Wrangler dev builds a class-name-to-policy map from exports and same-Worker bindings, the same way it handlesuseSQLite. Miniflare'sretryMaxAttempts/retryTimeoutMsoptions now configure the class, so they're rejected alongsidescriptName.cloudflare:durable-objectsjoins the plugin's list of built-in runtime modules, so Vite leaves the import for workerd instead of resolving it as a package. Wrangler already treats everycloudflare:*import as external.The generated Cap'n Proto types in miniflare come from the workerd PR's
workerd.capnp, because no workerd release includes the namespace field yet. The bump will regenerate them. Until then the installed workerd ignores the field, so the local retry policy has no effect, and the playground test forcloudflare:durable-objectsstays red.Known gaps:
wrangler devprocess, the call goes through the proxy's own namespace and uses the default policy, not the owner's.vite devand the Vitest plugin, Durable Objects run behind wrapper classes, so the runtime won't see theretryable()mark. The methods still run normally.