Skip to content

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

SymptomCOMPOSER_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 causetimeout 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.