synvael/docs/adr/0010-net-crate-async-runtime.md

2.2 KiB

0010. Dedicated net crate with a confined async runtime

  • Status: Accepted
  • Date: 2026-07-12

Context

The network transport is QUIC via quinn which is an asynchronous library built on the tokio runtime and requires TLS 1.3 through rustls. These are heavy dependencies that pull an entire async ecosystem into the build.

The shared crate is mandated to stay lean and dependency-light: it is the protocol/data layer, holding pure serde message types with no async, rendering, or engine internals. Placing transport code in shared would violate that mandate and force every consumer of the protocol types to compile tokio and rustls. At the same time, the simulation is synchronous: the server runs a synchronous bevy_ecs loop and the client runs a synchronous winit event loop. Introducing an async runtime must not turn those loops async or leak tokio throughout the workspace.

Decision

Transport lives in a dedicated net crate, separate from shared, and the tokio runtime is confined to it.

  • net owns the quinn, tokio, and rustls dependencies, plus the QUIC endpoints, connection lifecycle, and wire framing.
  • shared continues to hold only the protocol message types (serde, no async).
  • Both client and server depend on net.
  • The async runtime is bridged to the synchronous simulation over channels (crossbeam-channel), consistent with the message-passing concurrency model in AGENTS.md. The synchronous loops never .await; they send and receive protocol messages across the boundary.

Consequences

  • shared stays lean: consumers of the protocol types do not compile the async stack.
  • The async surface is quarantined. Only net deals with tokio, keeping the server and client loops synchronous and unchanged.
  • The workspace now has six crates. net sits between shared (types it carries) and the two binaries (which drive it).
  • The channel bridge is an explicit boundary that must be maintained: work crossing between the async runtime and the sync simulation flows through channels, never through shared async state or by making the sim async.
  • A crypto provider backend is required by rustls; the transport code must install one before building QUIC configuration.