diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ab72c6..b5a0667 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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-`, `rabbit-`, `wolf-`, and `partnership-` instead of `entity-`. - Rabbits killed by hunters no longer move or breed later in the same tick. diff --git a/Dockerfile b/Dockerfile index 30b7624..4a72737 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 diff --git a/README.md b/README.md index 99b7297..e3ccbfb 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/build.rs b/build.rs index 80e1f67..01279a1 100644 --- a/build.rs +++ b/build.rs @@ -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([