Skip to content

Durable Object reactivation stalls 3–28s before JS RPC handler (minimal repro + traces) #8010

Open

Description

@acchou

Summary

On hosted Cloudflare Workers, a minimal SQLite-backed Durable Object intermittently waits 3–28 seconds before its JavaScript RPC handler begins. One captured call took 27,844 ms at the caller / 27,888 ms at the HTTP client; the target native invocation reported 27,830 ms wall time and 0 ms CPU. The handler does only a synchronous read of one never-written key and returns diagnostic fields.

Reproduction and exported traces: https://github.com/acchou/cloudflare-do-activation-repro

This is a hosted-platform report; I have not reproduced the delay in local workerd. I am filing here because the observed boundary is Durable Object RPC/activation, with related context in #7607. I do not know the internal cause.

Minimal reproduction

Pinned Worker source. The repo contains the measured Worker logic, a standalone idle/repeat runner, and sanitized synthetic evidence. No application service bindings, user data, external database, AI, or billing code are involved.

npm ci
npm run check
npm test
npx wrangler login
npm run setup
npm run deploy
npm run probe -- --objects-per-hint 6 --cycles 10 --idle-ms 25000
npm run cleanup

The path is HTTP Worker → Caller DO → Target DO. Target.ping() reads ctx.storage.kv.get('never-written') and returns entry time, instance UUID, isolate UUID, sequence and object ID. There are no application writes, timers, external requests, or initialization tasks in that handler. A separate location probe runs outside the measured ping.

The runner uses fresh object identities with auto, wnam, enam and weur hints, rotates callers, leaves objects idle, then pairs each first call with an immediate repeat. The failure is intermittent and identity-dependent; a fresh deployment is not guaranteed to hit a slow placement.

Expected / actual

Expected: after ordinary routing and activation overhead, this minimal handler should return promptly.

Actual: the caller and HTTP client occasionally wait seconds before handler entry. In the recorded study, all 18 calls over one second were first pings on their in-memory object instances. The 1,600 later pings peaked at 583 ms. An object can reactivate in an already-observed JS isolate, so this is not necessarily a full isolate cold start.

A fresh enam replacement placed in ORD subsequently stalled on five of six controlled reopens (3,726–16,925 ms), while its immediate repeats were all ≤83 ms. A newly created caller in DFW also hit the ORD delay. The original IAD object later recovered without changing identity. Renaming therefore did not reliably solve this case.

Trace evidence

Measured 2026-10-26 20:24:17.963–20:31:43.270 UTC, paid Workers account, compatibility date 2026-04-09, Wrangler 4.151.1. Worker codex-placement-446b6c, version 0c5183b4-c380-4983-bf82-15e3274012ba. The temporary Worker and its namespaces have since been deleted. Account ID can be supplied privately if required.

Trace ID Path Awaited RPC Relevant timing
3612b97993290a98b4b86358d61b68d1 SJC → ORD 27,844 ms Target native wall 27,830 ms, CPU 0 ms; handler starts at the end
1c7b4d4cef630ccb622c22de9f3719b7 LAX → ORD 7,566 ms Target native invocation 7,479 ms, almost entirely before JS handler
5e02221d0a74158bdc23d02dd212ce3d SJC → IAD 11,875 ms Target native invocation only 2 ms; delay occurs earlier in dispatch

For the 27.844-second example:

  • Caller dispatch: 20:27:02.142 UTC.
  • Target handler entry: 20:27:29.957 UTC.
  • Target object: f5547a44420b5abe411ba3c4e47654228210248ad98afc31ad68338d03a11c4b.
  • Caller object: d38dbb929e143dc96ead34f507eb4dce8ef1e37182c9e051c2c7407f4a553fe5.
  • Probe ID: efd651f2-6ae1-44bc-90e5-2b2d2c2ec08b.

The evidence directory contains all 2,016 synthetic probe records and four compact trace exports retaining native span relationships/timestamps. Native spans corroborated the self-reported locations of all 72 targets across 15 colos. The exports omit account identifiers, credentials, IP addresses and unrelated logs.

Interpretation / question

The independent HTTP and caller timings confirm a real stall, not just a long-lived completed trace span. Cross-host entry-time subtraction is supporting evidence; I rely primarily on those same-process durations and native spans. The data locates waits before application work but does not identify storage activation, scheduling, routing, or a physical host issue.

Unlike #7607's reported delays on running objects, this sample's long delays occur on object reactivation. Could Cloudflare inspect the saved object IDs/timestamps for activation or RPC dispatch delays, and advise whether this belongs to the same platform issue or a separate one?

Activity

  1. acchou commented on Oct 26, 2026

    @acchou
    Author

    Concurrency follow-up: additional requests also wait

    I tested what happens when more requests are sent to the same target while its first RPC is stalled. Full results and reproduction instructions, all request records, and grouped comparisons are now published.

    Result: 11 stalls across 832 primary calls, with all 33 follow-up requests waiting until the original target handler began. The stalls affected three objects and ranged from 1,180 to 9,913 ms. In every group, all four handlers entered in the same recorded millisecond on the same object ID and instance UUID, with sequence numbers 1–4. No follow-up bypassed the wait.

    Method

    Fresh temporary deployment; 64 target identities split evenly between auto/wnam/enam/weur, eight warmed callers, initial access plus twelve rounds after 25 seconds idle. At most four primary groups ran concurrently. When a primary remained pending after one second, the driver sent:

    1. Another RPC through a new stub in the same caller DO.
    2. An RPC through a different caller DO.
    3. A direct stateless Worker → Target RPC.

    Actual server-side dispatch timestamps confirm every follow-up was sent before the original target handler entered. All 873 HTTP requests succeeded (832 primary + 33 follow-ups + 8 warm-ups). The target handler is unchanged from the original report. Runnable driver; use npm run concurrency after setup/deploy.

    Longest example

    Request Dispatched after original Awaited RPC
    Original 0 ms 9,913 ms
    Direct Worker → Target 985 ms 8,930 ms
    Different caller 994 ms 8,919 ms
    Same caller, new stub 1,042 ms 8,872 ms

    Original dispatch: 2026-10-26 20:45:47.279 UTC. All four target handlers entered at 20:45:57.183 UTC.

    • Target in LAX: 09bcac9064d49073019c70a4adb3cddc11d4821383ff05a97a5c879941ec776f.
    • Original probe: 7b1a330b-2722-4772-8c9d-06a193f036b3.
    • Trace cc85086d038328fc95703a8d624d54a6: target recorded 0 ms CPU, 8,865 ms native wall time; its native invocation started after the follow-ups, with 8,843 ms before JavaScript handler entry.
    • Second trace: 4,777 ms original RPC: same four-call pattern, target 1 ms CPU.

    These measurements are consistent with a shared wait before target execution, rather than only the original caller being delayed. They do not identify the internal cause. Sending follow-ups could affect activation timing, so this is not a counterfactual measurement of how long the original would have waited alone. Unlike some duplicates in #7607, none here entered ahead of the original.

    The temporary Worker do-activation-d5f54eab08f7 (version ab14e375-2df7-4ab8-b852-34db63dcd6fb) was deleted after this run. The public exports omit account identifiers, credentials, IP addresses and request headers. Eight evidence/packaging checks and the typecheck pass.

    Could you check whether the shared pre-handler wait across independent callers narrows down the activation/dispatch mechanism involved?

  2. danlapid commented on Oct 27, 2026

    @danlapid
    Collaborator

    Just following up that while I don't have an answer yet, the team is actively taking a look and investigating.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions