dev-server.sh: a global pidfile makes one worktree claim another's server #54

Closed
opened 2026-08-20 07:52:01 +00:00 by yuris · 0 comments
Owner

Found while working PR #53 (release-gate archive fixes), not fixed there — out of scope, and adjacent to #50.

Symptom

dev/tools/dev-server.sh reported server already running at http://127.0.0.1:5701 (pid 3339071) when that pid was actually serving port 3000, then failed to connect.

Root cause

Two things combine:

  • dev-server.sh:26 defaults STATE to a global /tmp/spacetimedb-defold, not a per-worktree path. So every worktree and every concurrent invocation shares one pidfile.
  • server_pid() at :36-42 only does kill -0 on the recorded pid. It never checks that the process is serving this $PORT.

So a live server on any port satisfies the check for a request about any other port, and the script reports a server that is not there.

Why it matters now

This bit three separate agents during the #24 push, each working a different branch in its own worktree. The workaround is always STDB_STATE_DIR, and every harness invocation in this repo now sets it — but the default is the trap, and a contributor with one checkout will hit it the first time they run two ports.

#50 hardened the readiness half of this script (the port answering is not proof our server is the one answering) and moved the stray-server refusal ahead of the spawn. This is the same class of bug one level up: the pidfile is not proof either.

Fix

Either derive STATE from $PORT so pidfiles cannot collide, or have server_pid() verify the recorded pid actually holds $PORT — ss -ltnp already gives that, and :80-82 reads it for the stray-server message.

The second is smaller and closes the case where two ports legitimately want two servers. #50's own comment makes the argument: "A ready port is not proof OUR server is the one answering." A live pid is not proof it is ours either.

Not blocking

dev/ is export-ignored, so this is harness ergonomics, not shipped behaviour. Not a v1.0 blocker.

Found while working PR #53 (release-gate archive fixes), not fixed there — out of scope, and adjacent to #50. ## Symptom `dev/tools/dev-server.sh` reported `server already running at http://127.0.0.1:5701 (pid 3339071)` when that pid was actually serving **port 3000**, then failed to connect. ## Root cause Two things combine: - `dev-server.sh:26` defaults `STATE` to a **global** `/tmp/spacetimedb-defold`, not a per-worktree path. So every worktree and every concurrent invocation shares one pidfile. - `server_pid()` at `:36-42` only does `kill -0` on the recorded pid. It never checks that the process is serving **this** `$PORT`. So a live server on any port satisfies the check for a request about any other port, and the script reports a server that is not there. ## Why it matters now This bit three separate agents during the #24 push, each working a different branch in its own worktree. The workaround is always `STDB_STATE_DIR`, and every harness invocation in this repo now sets it — but the default is the trap, and a contributor with one checkout will hit it the first time they run two ports. #50 hardened the *readiness* half of this script (the port answering is not proof our server is the one answering) and moved the stray-server refusal ahead of the spawn. This is the same class of bug one level up: **the pidfile is not proof either.** ## Fix Either derive `STATE` from `$PORT` so pidfiles cannot collide, or have `server_pid()` verify the recorded pid actually holds `$PORT` — `ss -ltnp` already gives that, and `:80-82` reads it for the stray-server message. The second is smaller and closes the case where two ports legitimately want two servers. #50's own comment makes the argument: *"A ready port is not proof OUR server is the one answering."* A live pid is not proof it is ours either. ## Not blocking `dev/` is export-ignored, so this is harness ergonomics, not shipped behaviour. Not a v1.0 blocker.
yuris closed this issue 2026-08-20 14:12:29 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
yuris/spacetimedb-defold#54
No description provided.