Add the Rust I/O backend: tokio event loop + tokio sockets - #7000
Open
danlapid wants to merge 1 commit into
Open
Add the Rust I/O backend: tokio event loop + tokio sockets#7000danlapid wants to merge 1 commit into
danlapid wants to merge 1 commit into
Conversation
Contributor
|
APIError: Invalid Anthropic API Key |
2 similar comments
Contributor
|
APIError: Invalid Anthropic API Key |
Contributor
|
APIError: Invalid Anthropic API Key |
Contributor
|
@danlapid Bonk workflow failed. Check the logs for details. View workflow run · To retry, trigger Bonk again. |
|
The generated output of |
danlapid
force-pushed
the
dlapid/rustIo
branch
2 times, most recently
from
August 14, 2026 03:00
ac4c4e3 to
2d5356d
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #7000 +/- ##
==========================================
- Coverage 67.80% 67.42% -0.38%
==========================================
Files 467 492 +25
Lines 132179 134580 +2401
Branches 21462 21597 +135
==========================================
+ Hits 89622 90743 +1121
- Misses 29486 30719 +1233
- Partials 13071 13118 +47 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
danlapid
force-pushed
the
dlapid/rustIo
branch
3 times, most recently
from
August 14, 2026 04:37
a48b1f5 to
d9c379a
Compare
…ault This is the first stage of running workerd on a Rust I/O stack. Under --//:io_backend=rust (the new default; --//:io_backend=cxx restores the all-C++ build byte-for-byte), the process event loop is tokio and every socket, stream, and listener is tokio-backed. Everything above the stream layer -- kj-http, kj-tls, capnp-rpc, and all of workerd -- is unchanged C++ running over those streams: same request paths, same wire bytes. Why compile-time selection and not a runtime flag: a binary with both I/O stacks linked can silently fall back to the C++ path and give false confidence. In the rust config the concrete kj OS I/O layer (@capnp-cpp//src/kj:kj-async-os) is not linked at all, so an unmigrated path is a build failure, and a build-graph aspect (//src/workerd/server:rust-io-hermeticity, run explicitly by CI) fails analysis if any dependency edge reaches it -- catching the double-definition failure mode that a static link may otherwise resolve silently in either direction. The pieces: * src/rust/cxx/kj-rs-tokio -- the guest event loop: a kj::EventPort that parks inside tokio's block_on, so one thread drives kj events and tokio's reactor and timers together. Includes a hi-res timer source (kj timers are sub-millisecond; tokio's wheel is ~1ms) and the arm-nudge hook that keeps same-thread event arms from being lost while parked. * src/rust/cxx/kj-rs-io -- the I/O layer: kj::Network, kj::ConnectionReceiver, and kj::AsyncIoStream implemented over tokio sockets, with same-thread pure-Rust DNS resolution, sockaddr/sockopt passthrough, signal-based drain, a --watch file watcher (line-for-line port of the kj-mode watcher, waiting through tokio's AsyncFd), a faithful port of kj's NetworkFilter (restrictPeers/SSRF parity), and a native-serve seam (unwrap / fd / pump tiers) that later stages use to hand accepted connections to Rust servers. * kj-rs bridge rework -- "a kj Event is the Waker": bridged futures wake by arming the awaiting kj Event directly. The cross-thread waker machinery (ArcWaker, CrossThreadPromiseFulfiller plumbing) is deleted under the single-thread axiom; what remains is two concrete waker types (a stack-owned PollWaker and a kj::Refcounted FutureWakerCell) trading real kj::Rc handles across the FFI. Ownership crosses the bridge as smart pointers everywhere except the one RawWaker data slot that std defines as a raw pointer. The generic LinkedGroup library is replaced by a purpose-built two-field intrusive weak link. * Seams in workerd proper: kj::setupAsyncIo() is supplied per-backend by //src/workerd/util:setup-async-io (no kj source changes, no #if at any call site), and the CLI's --watch/SIGTERM divergence lives behind //src/workerd/server:cli-io-backend. The WORKERD_RUST_IO_BACKEND_RUST #if exists in exactly three targets, via rust_io_backend_local_defines(). Safety posture: every crate is #![deny(unsafe_code)] at the root, with unsafe quarantined into named per-crate FFI islands; the serve/pump path is compiler-checked end to end (streams cross as owned KjOwn, driven through typed read/write halves that encode kj's one-read-one-write stream contract in the borrow checker).
danlapid
force-pushed
the
dlapid/rustIo
branch
from
August 14, 2026 04:46
d9c379a to
94c5a17
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is the first stage of running workerd on a Rust I/O stack. Under --//:io_backend=rust (the new default; --//:io_backend=cxx restores the all-C++ build byte-for-byte), the process event loop is tokio and every socket, stream, and listener is tokio-backed. Everything above the stream layer -- kj-http, kj-tls, capnp-rpc, and all of workerd -- is unchanged C++ running over those streams: same request paths, same wire bytes.
Why compile-time selection and not a runtime flag: a binary with both I/O stacks linked can silently fall back to the C++ path and give false confidence. In the rust config the concrete kj OS I/O layer (@capnp-cpp//src/kj:kj-async-os) is not linked at all, so an unmigrated path is a build failure, and a build-graph aspect
(//src/workerd/server:rust-io-hermeticity, run explicitly by CI) fails analysis if any dependency edge reaches it -- catching the double-definition failure mode that a static link may otherwise resolve silently in either direction.
The pieces:
src/rust/cxx/kj-rs-tokio -- the guest event loop: a kj::EventPort that parks inside tokio's block_on, so one thread drives kj events and tokio's reactor and timers together. Includes a hi-res timer source (kj timers are sub-millisecond; tokio's wheel is ~1ms) and the arm-nudge hook that keeps same-thread event arms from being lost while parked.
src/rust/cxx/kj-rs-io -- the I/O layer: kj::Network, kj::ConnectionReceiver, and kj::AsyncIoStream implemented over tokio sockets, with same-thread pure-Rust DNS resolution, sockaddr/sockopt passthrough, signal-based drain, a --watch file watcher (line-for-line port of the kj-mode watcher, waiting through tokio's AsyncFd), a faithful port of kj's NetworkFilter (restrictPeers/SSRF parity), and a native-serve seam (unwrap / fd / pump tiers) that later stages use to hand accepted connections to Rust servers.
kj-rs bridge rework -- "a kj Event is the Waker": bridged futures wake by arming the awaiting kj Event directly. The cross-thread waker machinery (ArcWaker, CrossThreadPromiseFulfiller plumbing) is deleted under the single-thread axiom; what remains is two concrete waker types (a stack-owned PollWaker and a kj::Refcounted FutureWakerCell) trading real kj::Rc handles across the FFI. Ownership crosses the bridge as smart pointers everywhere except the one RawWaker data slot that std defines as a raw pointer. The generic LinkedGroup library is replaced by a purpose-built two-field intrusive weak link.
Seams in workerd proper: kj::setupAsyncIo() is supplied per-backend by //src/workerd/util:setup-async-io (no kj source changes, no #if at any call site), and the CLI's --watch/SIGTERM divergence lives behind //src/workerd/server:cli-io-backend. The WORKERD_RUST_IO_BACKEND_RUST #if exists in exactly three targets, via rust_io_backend_local_defines().
Safety posture: every crate is #![deny(unsafe_code)] at the root, with unsafe quarantined into named per-crate FFI islands; the serve/pump path is compiler-checked end to end (streams cross as owned KjOwn, driven through typed read/write halves that encode kj's one-read-one-write stream contract in the borrow checker).