Appearance
date: 2026-06-12 tags: [pest-browser, playwright, timeout, shell, run-server] status: active graduated_to:
A capped browser-test run piped to | tail hangs forever on the orphaned run-server
Symptom — COMPOSER_ALLOW_SUPERUSER=1 timeout 240 vendor/bin/pest tests/Browser/X --compact | tail -6 kept "running" for 20+ minutes although the cap was 240s. The cap was not broken.
Root cause — timeout did kill pest at 240s, but a Pest browser run leaves an orphaned playwright run-server child that inherited the pipe's write file descriptor. tail blocks until EOF on the pipe, and EOF never comes while the orphan holds the write end open — so the shell hangs long after pest is dead. Separately, pkill -f "run-server" matches the running pkill's own command line, SIGTERMs its own shell, and exits 144 (128+16) without killing the orphan.
Fix — for capped browser runs: redirect to a file instead of piping (> /tmp/x.log 2>&1, then read the file) so no pipe waits on the orphan's fd; use timeout -k 10 240 to force-kill a pest that ignores SIGTERM; and kill a lingering server by PID (ps … | grep "run-serve[r]"), never with a pkill -f pattern that appears in the kill command itself.
Guard — this learning. Extends 2026-06-12-pest-browser-works-in-web-container.md, which flags the orphaned run-server but not the pipe-EOF hang or the pkill self-match.