fix(ci): reap whole server tree in installer smoke test so it can't hang 6h (#7981)

The "Installer test" workflow has hung for 6 hours (until GitHub's job
ceiling cancels it) on every ubuntu/macos run since v3.2.0. The smoke
test starts `pnpm run prod` in the background, confirms /api responds,
then tears it down with:

    kill "$PID"
    wait "$PID"

`pnpm run prod` is a nested launcher (pnpm -> pnpm --filter -> node), so
$PID is only the outer pnpm. SIGTERM is forwarded down the chain and the
script then `wait`s on it, but if the node server doesn't exit (e.g. a
live flush timer keeping the event loop alive) the wait blocks forever
and the step never releases its output pipe -> 6h hang. Windows passed
because it uses `Stop-Process -Force`.

Fix the teardown to be robust regardless of server shutdown behaviour:
- `set -m` so the launcher gets its own process group
- kill the whole group (SIGTERM, then SIGKILL fallback) via a trap
- drop the blocking `wait`
- add `timeout-minutes: 8` to both smoke steps as a hard backstop so a
  future hang fails in minutes, not 6 hours

This unblocks CI on PRs that touch the installer workflow. The
underlying clean-shutdown regression (server not exiting on SIGTERM,
likely the ueberDB flush-timer setInterval) is tracked separately.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
John McLear 2026-06-19 11:37:04 +01:00 committed by GitHub
parent 2109c05ad4
commit 32249d99e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -70,13 +70,30 @@ jobs:
- name: Smoke test - start Etherpad and curl /api
shell: bash
# Hard backstop: if teardown ever fails to reap the server the step
# fails in minutes instead of burning to GitHub's 6h job ceiling.
timeout-minutes: 8
env:
ETHERPAD_DIR: ${{ runner.temp }}/etherpad-installer-test
run: |
set -eu
# Enable job control so the backgrounded launcher gets its own
# process group, letting us reap the whole pnpm -> node tree below.
set -m
cd "$ETHERPAD_DIR"
pnpm run prod >/tmp/etherpad.log 2>&1 &
PID=$!
# `pnpm run prod` is a nested launcher (pnpm -> pnpm --filter -> node),
# so killing $PID alone orphans the node server, which keeps the step's
# output pipe open and hangs CI. Kill the entire process group, with a
# SIGKILL fallback in case SIGTERM is swallowed (e.g. a live flush timer
# keeping the event loop alive), so the step always exits cleanly.
reap() {
kill -TERM "-$PID" 2>/dev/null || true
sleep 5
kill -KILL "-$PID" 2>/dev/null || true
}
trap reap EXIT
# Wait up to 60s for the API to come up.
ok=0
for i in $(seq 1 60); do
@ -90,11 +107,8 @@ jobs:
if [ "$ok" != "1" ]; then
echo "Etherpad did not start within 60s. Last 200 lines of log:" >&2
tail -200 /tmp/etherpad.log >&2 || true
kill "$PID" 2>/dev/null || true
exit 1
fi
kill "$PID" 2>/dev/null || true
wait "$PID" 2>/dev/null || true
installer-windows:
name: end-to-end install (windows-latest)
@ -131,6 +145,7 @@ jobs:
- name: Smoke test - start Etherpad and curl /api
shell: pwsh
timeout-minutes: 8
env:
ETHERPAD_DIR: ${{ runner.temp }}\etherpad-installer-test
run: |