Repository navigation
v2.30.0: Shell-free argv arrays for ready_cmd and health_cmd, and pitchfork wait follows restarts
ready_cmd and health_cmd now accept argv arrays, so probes can run without a shell. run templates can use variables that only mise knows, and a new restarting status lets pitchfork wait keep following a daemon through restarts. The release also fixes a long list of supervisor lifecycle bugs: shutdown, stop order, settings that persisted after being removed from config, disabled daemons, ad-hoc restarts and cron retries. It also fixes Windows process cleanup and macOS boot crash recovery.
Added
-
argv arrays for
ready_cmdandhealth_cmd(#1012, #1015) by @Marukome0743. Both fields now take the same array asrun, either as the shorthand or asrunin the object form. The program gets each argument exactly as written, without going through a shell, so spaces, quotes,$,%and&are passed through unchanged. Each argument's templates are rendered separately.[daemons.database] run = ["postgres", "-D", "data"] ready_cmd = ["pg_isready", "-h", "127.0.0.1"] health_cmd = { run = ["pg_isready", "-h", "127.0.0.1"], interval = "10s", timeout = "5s" }
Without a shell,
$PORTin an argument stays as the literal text.PORTis still set in the environment, and you can keep using the string form if the port needs to be in an argument. If an array is empty, has an empty program or starts with"exec", the config fails to load. The string form and the--ready-cmd,--cmdand--health-cmdflags are unchanged. -
runtemplates can use mise-only variables (#966) by @jdx. Pitchfork may not be able to render a daemon'srun, for example when it uses a mise[vars]entry or a mise-only filter. If the daemon runs undermise x(mise = trueorgeneral.mise), pitchfork now passes the command through unrendered. It also puts its own template context inPITCHFORK_TEMPLATE_CONTEXTso mise can render the whole command.[daemons.api] run = "exec node server.js --port {{ daemons.redis.port }} --title {{ vars.title | quote }}" mise = true
This needs a mise release that includes jdx/mise#13894. Older mise versions leave the tags unrendered. Only
runis deferred:env, hooks and the ready and health fields still have to use variables pitchfork defines. Without mise, an unknown variable is still an error. If mise is enabled but its binary can't be found, the start fails.
Changed
- New
restartingstatus, andpitchfork waitfollows restarts (#992) by @jdx. A daemon being restarted by a file-watch change,pitchfork restartorstart --forcenow showsrestartinguntil its new process starts. Before, it briefly showedstopped. The status appears inlist(filter with--status restarting), the TUI, the web UI, JSON output and the HTTP API.pitchfork waitnow follows the daemon to its new process. Pass--exit-on-restartto get the old behavior, where a restart ends the wait with exit 0. Astopissued during a restart cancels the restart. pitchfork waitkeeps waiting through retries (#979) by @Marukome0743. If a failed daemon still hasretryattempts left,waitkeeps waiting. It exits 0 if a retry succeeds, or with the last attempt's exit code once all attempts have failed.pitchfork stopsucceeds when no supervisor is running (#991) by @jdx. It printsSupervisor is not running, nothing to stopand exits 0, without starting a supervisor. It also marks the targeted daemons stopped, so the next supervisor won't restart them. If a crashed supervisor left daemon processes running,stopfails, lists them, and tells you to runpitchfork supervisor startfirst.- Minimum supported Rust version is now 1.95 (#960) by @jdx. This only matters if you build from source. The previously declared 1.91 couldn't actually build the locked dependencies.
Fixed
Supervisor lifecycle and shutdown
pitchfork supervisor stopno longer kills the supervisor before it has stopped every daemon. The supervisor now works out how long its shutdown can take and reports that to the CLI. It also refuses new starts, cron runs and retries once shutdown has begun. A second signal during shutdown kills the remaining daemons instead of leaving them running without a supervisor (#973) by @Marukome0743.stop --all, group stops and supervisor shutdown now stop dependents before their dependencies, using the dependencies recorded when each daemon started. Before, running the command outside the project could stop them all at once (#986) by @Marukome0743.- A setting removed from
pitchfork.toml, such as a health check,env,cron, resource limits orstop_signal, no longer stays in effect after the next start (#967) by @Marukome0743. Likewise, removingauto = ["stop"]now stops a daemon from being autostopped after it restarts (#964) by @Marukome0743. - Disabled daemons are no longer started by cron, retries or
boot_start. Afterpitchfork enable, a cron schedule resumes at its next scheduled time without catching up on missed runs (#948) by @JamBalaya56562. pitchfork stopno longer panics when a daemon has a very largestop_signaltimeout (#938) by @JamBalaya56562.
Ad-hoc daemons and cron
- After
pitchfork stop, an ad-hoc daemon frompitchfork runcan be started again withstartorrestart, using its saved command. Starts that can't proceed now exit 1 and explain why, instead of warning and exiting 0 (#945) by @JamBalaya56562. - Restarting an ad-hoc daemon keeps the ready check, expected port, port bumping and
retryit was originally run with. Passing any readiness flag replaces the saved ready check (#943) by @JamBalaya56562. - Each scheduled cron run now gets its full
retrybudget. Before, once a run used up its retries, later runs weren't retried at all (#969) by @JamBalaya56562. - A cron schedule added to config no longer fires the command of an ad-hoc run that has the same id (#935) by @JamBalaya56562.
Config, hooks and mise
- A short daemon name now resolves to the current project's daemon before a slug that another project registered (#962) by @Marukome0743.
- If
pitchfork.tomldeclares a namespace,pitchfork daemons add --localno longer fails when it creates a newpitchfork.local.toml(#984) by @Marukome0743. - Configs that pitchfork writes itself no longer trigger warnings about the deprecated
expected_port,auto_bump_portandport_bump_attemptsfields. The warning now appears only when those fields disagree withport. Configs that only use the deprecated fields get a deprecation notice with a removal date of 2027-10-03 (#970, #976) by @JamBalaya56562 and @jdx. - Hooks now fire for daemons whose
dirpoints outside their project. This includes daemons that are adopted or retried from records saved by older versions (#981, #983) by @Marukome0743. mise = truedaemons now use their project'sgeneral.mise_bin, even when the supervisor was started in another directory. A relative path resolves from the project directory, andPITCHFORK_MISE_BINtakes precedence. Amise_binin user or system config is no longer treated as the project's (#968, #972) by @Marukome0743.watchnow works in project directories whose names contain glob characters such as[,{or*(#974) by @JamBalaya56562.
Logs and proxy
pitchfork logs -n N --jq EXPRnow shows the last N entries that match the filter. Before, it filtered only the last N entries (#985) by @JamBalaya56562.- logfmt values keep their original text unless they are plainly numbers, booleans or
null. Quoted values always stay strings. For example,id=007andcode="42"can now be matched with--fieldand--jq(#978) by @JamBalaya56562. - A daemon in a nested project is no longer shown the proxy URL of a root daemon with the same name (#977) by @JamBalaya56562.
- The proxy now uses a
--labelregistered from a linked git worktree, not just one registered from the primary checkout (#1011) by @jdx.
Platform-specific
- Windows:
pitchfork stopnow ends the daemon's whole process tree, including orphaned grandchildren and children that ignore Ctrl+C, by running each daemon in its own job object (#980, #997) by @JamBalaya56562. - Windows: with a PowerShell
general.windows_shellorgeneral.shell, arunstring that starts with a quoted program path, such as"C:\Program Files\app\app.exe" --port 8080, now starts correctly (#1016) by @JamBalaya56562. - macOS: launchd now restarts the boot supervisor after a crash, as systemd already does on Linux. A clean
pitchfork supervisor stopstill leaves it stopped. To upgrade an existing registration, re-runpitchfork boot enable. AKeepAlivepolicy you set yourself is kept (#1009, #1014) by @jdx and @Marukome0743. - Linux musl: pitchfork builds again for musl targets such as
x86_64-unknown-linux-musl(#1002) by @Marukome0743.
Full Changelog: v2.29.0...v2.30.0
💚 Sponsor pitchfork
pitchfork is built and maintained by @jdx, an open source developer at entire.io, the title sponsor of his open source work.
If pitchfork has a place in your development workflow, please consider becoming an individual or company sponsor. Your support funds ongoing development and helps keep pitchfork fast, free, and independent.