dev: cache Docker dependencies with cargo-chef

Cook native and Wasm dependencies in reusable Docker layers. Let the frontend build script use the cooked Wasm target directory while preserving local build defaults.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Steve Biedermann 2026-10-21 20:11:55 +02:00
parent 2305660d5a
commit ac5a40af37
4 changed files with 24 additions and 4 deletions

View File

@ -26,6 +26,7 @@ Notable changes to this project are documented here.
### Changed
- Cache native and Wasm dependencies with cargo-chef in Docker builds to speed up source-only rebuilds.
- Terminate shard processes when their simulation thread fails, so Docker can restart them instead of leaving an unresponsive shard and a repeatedly restarting gateway.
- People, rabbits, wolves, and partnerships are Picard actors that own their state; the world only reaches them through messages. Actors are named `person-<id>`, `rabbit-<id>`, `wolf-<id>`, and `partnership-<id>` instead of `entity-<id>`.
- Rabbits killed by hunters no longer move or breed later in the same tick.

View File

@ -1,9 +1,23 @@
FROM rust:1-bookworm AS builder
FROM rust:1-bookworm AS chef
WORKDIR /src
RUN rustup target add wasm32-unknown-unknown
RUN cargo install cargo-chef --version 0.1.78 --locked \
&& rustup target add wasm32-unknown-unknown
FROM chef AS planner
COPY . .
RUN cargo build --release --bin sim
RUN cargo chef prepare --recipe-path recipe.json
FROM chef AS builder
ENV SIM_UI_TARGET_DIR=/src/target/ui
COPY --from=planner /src/recipe.json recipe.json
RUN cargo chef cook --release --locked --recipe-path recipe.json --bin sim
RUN cargo chef cook --release --locked --recipe-path recipe.json \
--package ui --target wasm32-unknown-unknown --target-dir /src/target/ui
COPY . .
RUN cargo build --release --locked --bin sim
FROM debian:bookworm-slim

View File

@ -79,6 +79,8 @@ docker compose build
docker compose up -d --remove-orphans
```
The Docker build uses cargo-chef to cache native server and Wasm frontend dependencies separately. Source-only changes reuse these dependency layers; dependency or toolchain changes rebuild them. Inside the builder, `SIM_UI_TARGET_DIR` points the frontend build script at the cooked Wasm artifacts. Local builds retain their default frontend output directory unless this variable is set.
Open [http://localhost:7878](http://localhost:7878). The `shard_0_data`, `shard_1_data`, and `shard_2_data` volumes survive container restarts, `just stop`, and `docker compose down`.
If a shard's simulation thread fails, the shard exits with an error so Compose's restart policy can restart it. The gateway also exits when it loses a shard and reconnects on restart. Recovery uses the saved snapshots; if the shards' saved ticks or seeds do not match, the gateway starts a fresh world.

View File

@ -8,6 +8,7 @@ fn main() {
for p in ["ui/src", "ui/js", "ui/style.css", "ui/Cargo.toml"] {
println!("cargo:rerun-if-changed={p}");
}
println!("cargo:rerun-if-env-changed=SIM_UI_TARGET_DIR");
let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR"));
let pkg = out.join("ui-pkg");
let release = env::var("PROFILE").is_ok_and(|p| p == "release");
@ -15,7 +16,9 @@ fn main() {
ensure_wasm_target();
// A separate target dir avoids deadlocking on the outer build's lock.
let target_dir = out.join("ui-target");
let target_dir = env::var_os("SIM_UI_TARGET_DIR")
.map(PathBuf::from)
.unwrap_or_else(|| out.join("ui-target"));
let mut cargo = Command::new(env::var_os("CARGO").unwrap_or_else(|| "cargo".into()));
cargo
.args([