Research phase for browser-native swactor runtime: - constraints.md: wasm-threads (SharedArrayBuffer), Rust-only actors, COOP/COEP required, no new modules in src/ - research_synthesis.md: P0-P4 priority ranking, platform dependency analysis, ecosystem comparison (Lunatic, wasmCloud, Actix) - 6 feature-stage docs: platform abstraction → single-worker → multi-worker parallelism → feature parity → transport → DX - Key decision: SharedArrayBuffer + wasm-threads over postMessage isolation (swactor's shared-memory architecture demands it) Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski
5.5 KiB
5.5 KiB
Research Synthesis — In-Browser Swactor Runtime
Ecosystem Landscape
No established Rust actor framework runs natively in browsers. The closest projects:
- Lunatic — Erlang-inspired Wasm actor runtime using wasmtime (server-side, not browser). Uses preemptive scheduling and work-stealing. Not applicable to browser constraints.
- wasmCloud — CNCF distributed actor platform. Single-threaded actors, NATS-backed lattice. Cloud/edge focus, no browser target.
- Actix — Tokio-dependent, network stack doesn't compile for wasm32. Community attempts to port failed due to
net2/tokio dependencies.
Implication: swactor would be the first Rust actor runtime with true multi-threaded browser execution via wasm-threads. This is a differentiated position.
Existing Work in This Codebase
| Component | Status | Notes |
|---|---|---|
crates/wasm/ |
Basic PoC | Hardcoded Counter/Relay actors, manual tick, u32-only messages |
no_random feature |
Working | Deterministic address generation without getrandom |
tick() method |
Working | Single-threaded tick for manual driving |
| Actor watching | In core | ExitReason, ActorExited, on_actor_exit, WatchRegistry |
| swactor-std | Complete | StdExtension, naming, groups, monitoring, supervisor |
Platform Dependencies Analysis
Works as-is with wasm-threads
crossbeam-queue(ArrayQueue, SegQueue) — usescore::sync::atomicstd::sync::{Mutex, RwLock}— stdlib uses futex on wasm with atomicsstd::sync::atomic::*— maps to wasm atomic instructionsArc<T>— works with atomicsstd::sync::OnceLock— works with atomics
Requires platform abstraction (4 items)
std::thread::spawn→ Web Worker viaweb-sys::Workerthread::park_timeout/Thread::unpark→Atomics.wait/Atomics.notifythread::yield_now→ no-op (orAtomics.wait(0)as hint)std::time::Instant→web_time::Instant(drop-in crate)
Priority Ranking
P0 — Must Have (enables everything else)
- Platform abstraction layer — cfg-gated replacements for thread spawn, park/unpark, yield, Instant. Core swactor compiles for wasm32 with atomics.
- Single-worker browser runtime — Prove the runtime works in a browser. One Web Worker, auto-scheduled tick loop, generic JS API for spawn/send/recv.
- Multi-worker parallelism — N Web Workers sharing runtime state via SharedArrayBuffer. Full utilization of browser CPU cores.
P1 — Should Have (full actor system)
- Actor watching in browser — Death notifications, exit reasons. Already in core, just needs to compile and pass wasm tests.
- swactor-std in browser — Naming, groups, monitoring extensions. Compile and test for wasm32.
- Stats and introspection — Runtime stats accessible from JS. Worker info, actor counts, message throughput.
P2 — Important (distributed peer)
- WebSocket transport — Adapter implementing swactor's transport traits over WebSocket. Browser node joins a distributed cluster.
- Browser-to-browser transport foundation — WebRTC DataChannel scaffolding for future STUN/TURN.
P3 — Nice to Have (developer experience)
- TypeScript type generation — Derive TS interfaces from Rust actor message types.
- Build tooling — wasm-pack wrapper script, example project template, CI configuration.
- Browser dev tools — Actor inspector, message flow visualization, performance profiling.
P4 — Future (out of scope for this feature phase)
- STUN/TURN integration — Full NAT traversal for peer-to-peer browser connections.
- Hot code reload — Swap actor implementations without restarting the runtime.
- Wasm component model — Migrate from wasm-bindgen to component model when stabilized.
Key Design Decisions
| Decision | Choice | Rationale |
|---|---|---|
| Threading model | SharedArrayBuffer + wasm-threads | swactor's shared-memory architecture (Arc, crossbeam queues, atomics) maps directly. postMessage isolation would require a rewrite. |
| Scheduling | setTimeout(0) tight loop |
requestAnimationFrame caps at 60Hz. setTimeout(0) gives ~4ms resolution, sufficient for actor ticks. For rendering-coupled actors, RAF can be opt-in. |
| Actor definition | Rust only | Keeps the type system intact. JS actors would require dynamic dispatch and lose compile-time guarantees. |
| Platform abstraction approach | cfg-gated type aliases + inline functions | Minimal invasion. No trait-based HAL, no new modules. Just swap std::time::Instant → web_time::Instant etc. |
| Browser crate location | New crates/wasm-browser/ |
Clean separation from the existing PoC. The old crates/wasm/ can be deprecated or kept as a minimal example. |
Risk Assessment
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| crossbeam-queue doesn't compile for wasm32+atomics | Low | High | Test early in Stage 1. Fallback: thin wrapper over VecDeque behind cfg. |
| COOP/COEP headers break third-party integrations | Medium | Medium | Document clearly. This is the standard trade-off for SharedArrayBuffer apps. |
| Nightly Rust + build-std is unstable | Medium | Medium | Pin to a known-good nightly. Revisit when wasm-threads stabilizes. |
| Web Worker spawn latency | Low | Low | Spawn workers eagerly at runtime init, not per-actor. |
| Browser compatibility gaps | Low | Medium | Target Chrome/Firefox/Safari latest. All support SharedArrayBuffer since 2021. |