service: spawn body reader via wasm-bindgen-futures on wasm32#63
service: spawn body reader via wasm-bindgen-futures on wasm32#63connyay wants to merge 4 commits intoanthropics:mainfrom
Conversation
`spawn_body_reader` runs the per-request envelope decoder in the background so bidi and client-streaming RPCs can read incoming messages while the handler is producing responses. It used `tokio::spawn`, which panics with "there is no reactor running, must be called from the context of a Tokio 1.x runtime" on `wasm32-unknown-unknown` targets (Cloudflare Workers, etc.), where the ambient executor is `wasm-bindgen-futures` rather than tokio. Server-streaming and unary RPCs worked on Workers, but bidi and client-streaming panicked the moment the first envelope was decoded. Under `cfg(target_arch = "wasm32")`, dispatch the reader future via `wasm_bindgen_futures::spawn_local` instead. `spawn_local` doesn't return a joinable handle, but the existing code only held the `JoinHandle` for lifetime association (don't abort early), so `None` works fine. `spawn_body_reader`'s return type and `StreamingResponseBody::with_reader_task` now take `Option<JoinHandle<()>>`. `tokio::sync::mpsc` keeps working unchanged; its internals only need wakers, which `wasm-bindgen-futures` provides. Adds a wasm32-only target dep on `wasm-bindgen-futures = "0.4"`. No behaviour change on native targets; the tokio path is unchanged. Verified end-to-end against a Cloudflare Worker via miniflare and `wrangler dev`: bidi calls now succeed, the handler is dispatched before the request body completes, and per-input echoes round-trip in ~1ms while the request stream is still open. See https://github.com/connyay/example-connectrpc-worker for a runnable example (clock = server-stream, echo = bidi, heartbeat = full-duplex bidi probe). Scope here is server-side handler dispatch. `call_bidi_stream` in `client/mod.rs` also calls `tokio::spawn`, but the rest of the `client` module already requires hyper / tokio-net features that don't compile on wasm32. Wasm client transports are a separate concern handled by user-supplied `ClientTransport` impls (see `examples/wasm-client`). Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
|
All contributors have signed the CLA ✍️ ✅ |
|
I have read the CLA Document and I hereby sign the CLA |
Replace the two inline cfg(target_arch) directives in spawn_body_reader with a single helper that owns the platform fork. The native variant takes Send + 'static and forwards to tokio::spawn; the wasm32 variant takes 'static and forwards to wasm_bindgen_futures::spawn_local, returning None for the join handle. The call site in spawn_body_reader is now cfg-free. The wasm hedge also drops out of with_reader_task's docstring; the Send-bound divergence and the no-abort policy live next to spawn_detached.
|
[claude code] Pushed a small fixup commit (d0ce6b0) extracting a Verified locally:
Happy to revert if you'd rather keep the original shape, but this gets the diff to a place we're comfortable approving and merging. |
|
The fixup looks great, thanks! |
Bumps `iainmcgin/cla-github-action` to `73f6929` and allowlists `noreply@anthropic.com`. The new revision adds email-based matching to the allowlist alongside the existing name-based match. AI assistants commonly add `Co-authored-by:` trailers like `Claude Opus 4.7 <noreply@anthropic.com>`, and the impersonation guard added in the previous bump correctly counts those as committers — without an email allowlist, every PR with such a trailer fails the CLA check. The new entry suppresses the synthetic identity once. The PR opener still has to sign. Tests on the action: 100/100 pass, including new cases for exact email match, `*@anthropic.com` glob, and the no-email-supplied path. Caught while reviewing PR #63 — connyay's commit there carries a `Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>` trailer that was failing the CLA check after the previous bump landed on main.
spawn_body_readerruns the per-request envelope decoder in the background so bidi and client-streaming RPCs can read incoming messages while the handler is producing responses. It usedtokio::spawn, which panics with "there is no reactor running, must be called from the context of a Tokio 1.x runtime" onwasm32-unknown-unknowntargets (Cloudflare Workers, etc.), where the ambient executor iswasm-bindgen-futuresrather than tokio. Server-streaming and unary RPCs worked on Workers, but bidi and client-streaming panicked the moment the first envelope was decoded.Under
cfg(target_arch = "wasm32"), dispatch the reader future viawasm_bindgen_futures::spawn_localinstead.spawn_localdoesn't return a joinable handle, but the existing code only held theJoinHandlefor lifetime association (don't abort early), soNoneworks fine.spawn_body_reader's return type andStreamingResponseBody::with_reader_tasknow takeOption<JoinHandle<()>>.tokio::sync::mpsckeeps working unchanged; its internals only need wakers, whichwasm-bindgen-futuresprovides.Adds a wasm32-only target dep on
wasm-bindgen-futures = "0.4". No behaviour change on native targets; the tokio path is unchanged.Verified end-to-end against a Cloudflare Worker via miniflare and
wrangler dev: bidi calls now succeed, the handler is dispatched before the request body completes, and per-input echoes round-trip in ~1ms while the request stream is still open. Seehttps://github.com/connyay/example-connectrpc-worker for a runnable example (clock = server-stream, echo = bidi, heartbeat = full-duplex bidi probe).
Scope here is server-side handler dispatch.
call_bidi_streaminclient/mod.rsalso callstokio::spawn, but the rest of theclientmodule already requires hyper / tokio-net features that don't compile on wasm32. Wasm client transports are a separate concern handled by user-suppliedClientTransportimpls (seeexamples/wasm-client).