Prompt file imported from dafrose/Cursor-Settings (
.cursor/commands/bench-kill-session.md). Copyright stays with the author.
Kill leftover processes from a previous Frappe bench development session (e.g. after bench start / honcho exited badly). Scope to one bench directory so other benches on the machine are not touched.
Why things “stick around” (honcho / dev server)
- Honcho (used by
bench start) stops all Procfile processes when any one of them exits. If you seeschedule.1 stopped (rc=0)(or another worker exiting) followed bysending SIGTERM to …, that cascade is honcho, not a random bug—fixing it usually means makingbench schedulestay running or adjusting the Procfile, not only killing orphans. bench serveoften uses the Werkzeug/Flask development server with a watchdog reloader (“Restarting with watchdog”). The child process may not includebench servein its command line, so matchers that only look forbench serve/gunicornmiss it.bench watchmay runnode esbuild(or similar) under yarn; children may show asnode …/esbuildand must still match the bench.
-
Resolve the bench root (directory that contains
Procfile). If the user did not give a path, infer from context (e.g. workspaceversion-15or whereverProcfilelives). Ask once if still ambiguous. -
Collect candidate PIDs for that bench only, then deduplicate. Use the shell.
A.
ps(macOS:ps -ax -o pid=,args=; Linux:ps -eo pid=,args=if needed)
Include a PID if the full command line contains the absolute bench root and matches any of:honchoredis-serverbench serve,bench watch,bench schedule,bench workergunicornsocketio.jsorfrappe/socketiopython/python3/Pythonand also (frappeorwerkzeugorsites/orbenchin a way that clearly indicates the dev app server or reloader—not unrelated scripts in the repo)nodeand also (esbuildorviteorrolluporsocketiooryarnwith paths under the bench)
B. Redis pidfiles (if present): read PIDs from
<bench>/config/pids/redis_cache.pidandredis_queue.pidand verify each PID is still running (kill -0).C. Redis listen ports: from
<bench>/config/redis_cache.confandredis_queue.conf, read theportlines. For each port, uselsof -ti tcp:<port> -sTCP:LISTEN(or equivalent) and keep a PID only ifpsshows it isredis-server.D. Bench “well-known” TCP ports (orphan dev server / socketio / watch)
These catch processes whose argv no longer mentionsbench serve:- Parse
--portfrom theweb:line inProcfile(if absent, default 8003 or readwebserver_portfrom<bench>/sites/common_site_config.jsonif present). - Read
socketio_portfrom<bench>/sites/common_site_config.jsonif present (typical 9003). - Optionally read
file_watcher_portfrom the same file (often used for live reload / esbuild; only kill ifpsshowsnodeor a clear bench-related command).
For each such port, take PIDs from
lsof -ti tcp:<port> -sTCP:LISTEN. Keep a PID only ifpsshows it is plausibly this bench (e.g.python/nodewith the bench path in the command line, or a path under<bench>/apps//<bench>/env/). Do not kill unrelated servers on the same port without that check. -
If there are no PIDs, say so and stop.
-
Otherwise print the bench root and the list of PIDs. If the user asked for a dry run / preview only, stop after printing.
-
Terminate: send SIGTERM to each PID, wait about one second, then SIGKILL any that are still alive. Report what was killed.
-
Do not kill processes whose command line does not tie them to that bench path (except redis matched via pidfile/port as above, and port D only after the plausibility check). Never kill the current session’s shell or unrelated system services.