playwright / supervisor.sh
cv3inx's picture
supervisor: stop swallowing API stdout
e2626df
Raw
History Blame Contribute Delete
3.24 kB
#!/bin/bash
# Supervisor for the playwright-api container.
#
# Two modes:
#
# 1) Standalone (HF Space): TURNSTILE_SOLVER_URL points at 127.0.0.1 /
# localhost. The bundled Python solver is started in the background
# and we wait for it before launching the API.
#
# 2) Compose: TURNSTILE_SOLVER_URL points at the sibling `turnstile-solver`
# service on the internal Docker network. We skip the bundled solver
# entirely (saves boot time and avoids the dep-install footgun) and
# just wait for the remote one to be healthy.
set -uo pipefail
API_PID=""
SOLVER_PID=""
SOLVER_PORT="${SOLVER_PORT:-9988}"
SOLVER_URL="${TURNSTILE_SOLVER_URL:-http://127.0.0.1:${SOLVER_PORT}}"
shutdown() {
echo "[supervisor] shutting down..."
[ -n "$API_PID" ] && kill -TERM "$API_PID" 2>/dev/null || true
[ -n "$SOLVER_PID" ] && kill -TERM "$SOLVER_PID" 2>/dev/null || true
wait 2>/dev/null
exit 0
}
trap shutdown SIGTERM SIGINT
# Decide whether the solver lives in this container.
case "$SOLVER_URL" in
*127.0.0.1*|*localhost*)
BUNDLED_SOLVER=1 ;;
*)
BUNDLED_SOLVER=0 ;;
esac
if [ "$BUNDLED_SOLVER" = "1" ]; then
if [ -f /app/solver/service.py ] && command -v python3 >/dev/null 2>&1; then
if python3 -c "import aiohttp" 2>/dev/null; then
echo "[supervisor] starting bundled turnstile-solver on :${SOLVER_PORT}..."
(
cd /app/solver
rm -f /tmp/.X*-lock /tmp/.X11-unix/X* 2>/dev/null || true
# stdbuf -oL forces line-buffered stdout so logs flush per line
# instead of being held back in sed's pipe buffer.
PORT="${SOLVER_PORT}" CAMOUFOX_HEADLESS="${CAMOUFOX_HEADLESS:-virtual}" \
PYTHONUNBUFFERED=1 \
stdbuf -oL -eL python3 service.py 2>&1 | stdbuf -oL sed -u 's/^/[solver] /'
) &
SOLVER_PID=$!
else
echo "[supervisor] solver deps missing (aiohttp) β€” bundled solver disabled"
fi
else
echo "[supervisor] bundled solver not present in image β€” skipping"
fi
else
echo "[supervisor] external solver configured: $SOLVER_URL β€” not starting bundled"
fi
echo "[supervisor] waiting for solver health at ${SOLVER_URL}..."
SOLVER_READY=0
for i in $(seq 1 60); do
if curl -fsS "${SOLVER_URL%/}/health" >/dev/null 2>&1; then
echo "[supervisor] solver healthy after ${i}s"
SOLVER_READY=1
break
fi
if [ "$BUNDLED_SOLVER" = "1" ] && [ -n "$SOLVER_PID" ] && ! kill -0 "$SOLVER_PID" 2>/dev/null; then
echo "[supervisor] bundled solver died during boot β€” continuing without it"
SOLVER_PID=""
break
fi
sleep 1
done
if [ "$SOLVER_READY" = "0" ]; then
echo "[supervisor] solver did not become healthy in 60s β€” API will start anyway"
echo "[supervisor] captcha.solveTurnstile() will fall back to local click only"
fi
echo "[supervisor] starting playwright-api on :${PORT:-7860}..."
# No prefix wrapper here β€” server.js already produces its own pretty,
# tabular log format. Run bun directly so we don't pipe through sed
# (which would buffer stdout) or lose ANSI colors.
bun /app/server.js &
API_PID=$!
wait -n "$API_PID" ${SOLVER_PID:+$SOLVER_PID} 2>/dev/null
EXIT_CODE=$?
echo "[supervisor] one process exited (status=$EXIT_CODE), shutting down others"
shutdown