# Description of Changes. Introduces deterministic runtime crate. Integrate it with RelationalDB. I think best steps to review: - Read the [README](https://github.com/clockworklabs/SpacetimeDB/blob/shub/sim/crates/runtime/README.md) of runtime crate. - Look at the integration with existing crates - `durability`, `core`, `snapshot`, etc. - Read runtime crate's code. Draft branch to Test code - https://github.com/clockworklabs/SpacetimeDB/pull/5019 # API and ABI breaking changes NA # Expected complexity level and risk Does not intend to change any production functionality, but it's big code. # Testing - new crate contains unit and integration tests. - Existing tests should work for production. --------- Signed-off-by: Shubham Mishra <shivam828787@gmail.com> Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
4.2 KiB
Welcome to the Matrix!
spacetimedb-runtime
spacetimedb-runtime is a runtime boundary that lets SpacetimeDB core code run under deterministic simulation testing (DST).
DST runs code inside a deterministic simulator that controls nondeterministic inputs instead of letting them come directly from the OS and real runtime environment. Given the same seed, the simulator should produce the same trace. When it finds a bug, the seed should be enough to reproduce that bug exactly.
For this to work, code under test must not read clocks, randomness, scheduling, I/O, or network behavior directly from the outer environment. Those effects need interfaces that production can implement with real runtime-backed services and DST can replace with simulated ones.
This crate provides the execution-control part of that boundary: spawning, timeouts, virtual time, deterministic randomness, task scheduling, and fault decisions. Storage, networking, and replication should be modeled through higher-level abstractions.
For a tracked view of what is currently under simulator control, what is only constrained by convention, and what still leaks host behavior, see DETERMINISM_COVERAGE.md.
Architecture
src/lib.rs exposes Handle, a small runtime handle shared code carries. It has two variants:
Handle::Tokio(TokioHandle)for real runtime execution.Handle::Simulation(sim::Handle)for deterministic simulation.
src/sim contains the simulation core. It is single-threaded and targets no_std + alloc. The module includes:
executor: single-threaded task scheduler with deterministic runnable selection.time: virtual clock, sleeps, and timeouts.rng: seeded deterministic randomness for scheduler and workload decisions.buggify: fault-injection surface. Calls rng to decide probabilistically whether to inject failures into simulated operations.node: node builders and node-local scheduling handles.
src/sim_std.rs contains std/OS glue around the simulator:
block_oninstalls simulation guards for tests running in a normal process.check_determinismreplays the same seeded workload twice and compares traces.- libc randomness hooks warn and delegate if code reaches OS entropy.
- Unix thread hooks reject accidental
std::thread::spawnwhile simulation is active.
Tokio integration is intentionally small and lives directly in src/lib.rs.
Feature flags:
tokio: enables the Tokio runtime backend and remains in the default feature set.simulation: enables the deterministic simulation runtime andsim_stdhelpers.
Design Principles
-
Single-threaded runtime. The simulator exposes interleaving and timeout bugs, but not bugs that require true parallel execution. The direction is to keep deep-core code single-threaded or close to thread-per-core; simulating real parallelism is out of scope.
-
No built-in network, storage, or I/O simulation. This crate provides deterministic execution primitives only. Higher-level harnesses should model message delivery, disk behavior, and failures.
-
Not a Tokio replacement. This crate does not aim to simulate APIs like
tokio::netortokio::fs. Code that depends on them needs a higher-level abstraction boundary. -
Zero dependency. The simulation core in
sim/is alreadyno_std + alloc. Thesim_stdmodule is a thin OS-facing wrapper — the std dependency lives there, not in the simulation core itself. It stays until the application logic above this crate also moves tono_std.
Current Limitations
-
One shared virtual clock. All simulated nodes share a single clock. This masks bugs related to timing mismatch across machines.
-
No good alternative for blocking APIs. The simulation backend has no
spawn_blockingpool or OS thread escape hatch. API likespawn_blockingorHandle::block_ondelegate to the single executor thread, so blocking inside them stalls all simulated tasks. The direction is to avoid relying on blocking semantics inside the simulation boundary. -
OS randomness is not controlled.
sim_stdwarns if code reaches OS entropy. The direction is to keep application code and testing harnesses off OS randomness entirely.