Skip to content

Add blockConcurrencyWhile binding for Durable Objects - #1039

Open
lukevalenta wants to merge 3 commits into
cloudflare:mainfrom
lukevalenta:lvalenta/do-async-init
Open

Add blockConcurrencyWhile binding for Durable Objects#1039
lukevalenta wants to merge 3 commits into
cloudflare:mainfrom
lukevalenta:lvalenta/do-async-init

Conversation

@lukevalenta

Copy link
Copy Markdown
Contributor

NOTE: I used AI to help draft this PR, but I understand and approve the code and think this would be a useful feature for the Rust bindings.

Bind the runtime's blockConcurrencyWhile via State::block_concurrency_while (errors reset the object) and block_concurrency_while_infallible (errors returned as values). This mostly addresses #177, but since a literal async constructor isn't supported we instead document a lazy-init handler pattern.

@codspeed-hq

codspeed-hq Bot commented Jul 31, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

✅ 2 untouched benchmarks


Comparing lukevalenta:lvalenta/do-async-init (9188a17) with main (5f2d6c9)

Open in CodSpeed
lukevalenta and others added 2 commits August 18, 2026 12:50
Bind the runtime's blockConcurrencyWhile via State::block_concurrency_while
(errors reset the object) and block_concurrency_while_infallible (errors
returned as values). Addresses cloudflare#177; a literal async constructor remains
unsupported, so document the lazy-init handler pattern.
The gate now closes as a side effect of the call rather than on first poll
of the returned future, so calling it un-awaited from new() gates all event
delivery during async initialization, matching the JavaScript constructor
idiom. The _infallible variant is dropped: errors as values are expressed
by returning them inside Ok.
@guybedford
guybedford force-pushed the lvalenta/do-async-init branch from 9188a17 to 79f7db0 Compare August 18, 2026 20:00
@guybedford

Copy link
Copy Markdown
Collaborator

Thanks for posting this one. To try to better align with the JS semantics I just posted up a change. AI summary below -

The original wrapper deferred the blockConcurrencyWhile call to first poll of the returned future, which silently diverged from JS semantics: in JS the gate closes as a side effect of the call, and awaiting the promise is optional. That call-time/await-time fusion is what made the constructor idiom impossible and forced the lazy-init pattern (which needs an initialized check replicated across every handler — fetch, alarm, all websocket callbacks — and breaks if any await precedes the check).

The reworked API is a single eager method:

pub fn block_concurrency_while<F, Fut, T>(&self, closure: F) -> impl Future<Output = Result<T>>

The JS call happens in the fn body (closure via once_into_js, so its lifetime is decoupled from the future). Both JS idioms then fall out of one signature: await it in a handler for an atomic critical section returning T, or call it un-awaited from new() to gate all event delivery during async init — exactly matching un-awaited blockConcurrencyWhile in a JS constructor. This also let me drop infallible: errors-as-values is just returning them inside Ok (T = Result<, E>), now covered by a doc note and a test.

Tests carried over with one strengthened: the lazy-init test became a constructor-gating test — new() fires the init (two awaits, 0-sentinel field), and the spec asserts the very first request already observes the loaded value with the closure having run exactly once. The RMW and reset-on-Err tests are unchanged and still pass against real workerd via miniflare.

guybedford
guybedford previously approved these changes Aug 18, 2026
@guybedford

Copy link
Copy Markdown
Collaborator

@lukevalenta would value your confirmation the changes I added work for your use case before landing further.

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

Labels

None yet

2 participants