anvil runner stop: graceful shutdown + PID file (foreground and service) #22
closed
Opened by cole.christensen@gmail.com
Links
No links yet.
Problem
`anvil runner start` has no clean way to be stopped from outside the process. Specifically:
- Foreground: `anvil runner start` listens only for SIGINT (Ctrl+C, see `src/runner/loop_runner.rs:50`). If backgrounded (`nohup anvil runner start &`), you have to find the PID via `pgrep` and `kill` manually.
- systemd / launchd service: `systemctl stop anvil-runner` sends SIGTERM, not SIGINT. The runner currently ignores SIGTERM, so the service stop is effectively a hard kill — jobs in flight get yanked instead of finishing.
- No `anvil runner stop` subcommand exists. `anvil runner service svc-stop` only covers the OS-service path.
Proposal
Three changes, all in one PR (tightly coupled):
- Write a PID file on `runner start` at `~/.anvil-runner/runner.pid` (path configurable via `–pid-file`, also stored in config). Removed on clean shutdown.
- Handle SIGTERM in addition to SIGINT. Both trigger the same graceful-shutdown path (existing `tokio::sync::Notify`). Jobs-in-flight get a configurable grace window (default 30s) to complete before force-exit.
- `anvil runner stop` subcommand: reads the PID file, sends SIGTERM, waits for the file to disappear (signaling clean exit), errors with timeout if not. `–force` falls through to SIGKILL after the timeout.
Side benefits
- `anvil runner service svc-stop` (systemd/launchd path) becomes truly graceful instead of a kill.
- The new `anvil runner stop` works regardless of how the runner was started.
- PID file enables future affordances like `anvil runner status` showing “running (PID 12345)”.
Acceptance criteria
- `anvil runner start` writes `runner.pid` and removes it on clean exit
- SIGTERM triggers the same graceful path as SIGINT
- Jobs in flight finish (or hit grace timeout) before exit
- `anvil runner stop` finds and signals the running instance
- `anvil runner stop` errors clearly if no PID file / stale PID
- `–force` adds SIGKILL fallback
- Tests: clap parsing for new `stop` subcommand + signal-handling unit test
Origin
User feedback: “we have things for the anvil runner being STARTED but not stopped. we need that both for the systemd style service and the non-[service]”.