hecks

Fargate’s persistent server keeps rust/host’s single mutex-guarded connection; a pool is deferred, not built

Status: Accepted — implemented. rust/host/src/server.rs (PR #773, HECKS_SERVE_MODE=1), reusing dispatch.rs’s existing Arc<Mutex<Client>>.

Context

rust/host has always run as a Lambda custom-runtime process (lambda_runtime::run(service_fn(...))), which hands the process one event at a time — there was never a real possibility of two dispatches overlapping in the same process. dispatch.rs already guards its single tokio_postgres::Client with a Mutex, but its own header comment on that choice was explicit that this was defensive, not load-bearing under Lambda: “if this process is ever invoked concurrently in-process (lambda_runtime’s default loop is one-event-at-a-time, but nothing in this crate depends on that staying true), two calls can’t interleave statements on the one connection this crate holds.”

Adding a persistent HTTP server (server.rs, for the new AwsFargate deploy target) makes that “ever” real: an axum listener can receive genuinely concurrent HTTP requests, so the mutex stopped being a defensive nicety and became the thing actually deciding whether concurrent writes are safe.

Decision

Keep the existing Arc<Mutex<Client>> as-is. Every write path (handle, handle_facts, handle_routed) already holds that lock for its full duration, including the WASM execution nested inside via spawn_blocking — so under the server, concurrent requests serialize on the write path but never interleave statements or corrupt state. Read paths (dispatch::read, snapshot queries) hold the lock only briefly, and wasmtime’s Engine/Module are already Arc-shared and safe to instantiate from multiple threads, so the actual computation still parallelizes; only the database write itself is single-threaded.

Verified against real concurrent load, not assumed: 10 concurrent HTTP requests dispatching the identical duplicate-identity CreatePizza command all returned 200 with no crash or deadlock, and exactly 1 of the 10 was actually journaled (confirmed by a follow-up read and a direct row count) — proof the mutex plus the domain’s own advisory-lock-based idempotency correctly serialize the write path rather than racing.

Consequences

Rejected alternatives