Skip to content

fix: pid reuse after reboot, missing pid in instance.json, Windows non-ASCII locale - #38

Merged
nicoloboschi merged 2 commits into
mainfrom
fix/pid-reuse-and-locale
Sep 14, 2026
Merged

nicoloboschi merged 2 commits into
mainfrom
fix/pid-reuse-and-locale

Conversation

@nicoloboschi

@nicoloboschi nicoloboschi commented Sep 14, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #37, fixes #36, fixes #35.

#37: saved pid reused after reboot

Every running check was kill -0 <saved pid>. After a reboot, macOS gave that pid to another process, so start refused forever. Worse, stop/drop could fall back to kill -9 on that unrelated process.

  • is_process_running is now is_postgres_process: the pid must be alive and its executable must be postgres (via ps -o comm= on Unix, QueryFullProcessImageNameW on Windows). pid 0 is rejected.
  • New running_pid(&info): the saved pid must also match <data_dir>/postmaster.pid. stop, drop, psql, install-extension and the health check use it.
  • start checks the pid in postmaster.pid rather than the saved one, and never removes the pidfile of a live postgres.
  • SIGKILL fallbacks only fire after re-checking that the pid is still postgres.

#36: instance.json without pid

InstanceInfo.pid is now Option<u32>, so a missing pid or null loads. 0 is treated as not running.

#35: Windows non-ASCII locale

postgresql_embedded gives no way to pass --locale to initdb. On Windows, when the data dir isn't initialized yet, pg0 now runs initdb itself with the crate's exact arguments plus --locale=C, and setup() then skips its own initdb. Existing clusters and Linux/macOS behavior are unchanged.

Testing

Unit tests (cargo test, now run in the macOS CI job; the suite wasn't run in CI before):

  • is_postgres_process: a live fake postgres counts; a live non-postgres pid (reused), pid 0, and an exited process don't.
  • running_pid: a matching live postgres counts; a missing/0 pid, a reused pid, a pid that doesn't match postmaster.pid, and a missing pidfile don't.
  • check_not_running (start's pre-check): refuses a live postmaster and keeps its pidfile; removes a reused-pid, garbage, or absent pidfile.
  • kill_if_postgres: leaves a non-postgres process alive; kills postgres.
  • wait_for_shutdown: not done while postgres is alive; done when the pid is reused and the pidfile is gone.
  • Health check: false for a reused pid and for no pid.
  • instance.json: missing pid, null pid, round trip.
  • init_data_dir: runs the real bundled initdb; asserts lc_* = C, password auth, temp password file removed.

Manual run on macOS: start → stop → remove pid → start ✅. pid=1 in both instance.json and postmaster.pid: info says not running, stop signals nothing, start recovers ✅. Double start still refuses ✅.

Windows: the Windows build and Windows SDK tests passed on the first commit, so QueryFullProcessImageNameW compiles and new clusters get initialized through the new initdb path.

…ale on Windows initdb

- Only treat an instance as running when the saved pid matches postmaster.pid
  and is a live postgres process, so a pid reused after reboot no longer
  blocks start or gets signalled by stop/drop (#37).
- Make InstanceInfo.pid optional so instance.json without pid (or null/0)
  loads (#36).
- On Windows, run initdb ourselves with --locale=C for new clusters so
  localized non-ASCII locale names don't fail (#35).
- Extract check_not_running (start's stale-pidfile handling) and
  kill_if_postgres (guarded SIGKILL fallback) so they can be tested.
- Tests: is_postgres_process, running_pid, check_not_running (live, reused,
  garbage, missing pidfile), kill_if_postgres, wait_for_shutdown with a
  reused pid, health check without a live postmaster, instance.json with
  missing/null pid and round-trip, and init_data_dir running the real
  bundled initdb with --locale=C.
- Run cargo test in the macOS CI job; the suite was never run in CI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant