Files
tfaour c6dad191fb
Build and push server image / test (push) Successful in 45s
Build and push server image / build-and-push (push) Successful in 4m17s
Build and push server image / deploy (push) Failing after 1m42s
Fetch headless Chromium at container startup instead of build time
build-and-push failed on the last deploy: chromium-headless-shell's
single ~181MB binary can't be split across Docker layers the way this
project's pip/npm installs were (those are many independently-
installable smaller packages; this is one file), and confirmed-failed
to push past the registry's per-layer size limit.

Moves the `playwright install chromium-headless-shell` step from the
Dockerfile to start.sh, caching into PLAYWRIGHT_BROWSERS_PATH on the
/data volume -- only the very first boot on a fresh volume downloads
it, every boot after that is a no-op check. The image itself no longer
grows by ~262MB, so nothing new gets pushed to the registry at all.
2026-07-31 02:18:36 +00:00

37 lines
1.8 KiB
Bash
Executable File

#!/bin/sh
# Starts render-service/ (whiteboard frame mode's Excalidraw-to-PNG
# sidecar, see its own README) in the background, bound to 127.0.0.1 --
# reachable from this container's Python process, never from outside it.
# Then execs uvicorn as the foreground/PID 1 process so it receives
# Docker's stop signal directly.
#
# Before either: fetch headless Chromium (app/html_render.py, the
# weather widget's opt-in "modern" render style) into
# PLAYWRIGHT_BROWSERS_PATH (set in the Dockerfile to a path on the /data
# volume) if it isn't already cached there -- see the Dockerfile's own
# comment for why this happens at startup instead of build time. Only
# the very first boot on a fresh volume actually downloads anything;
# every boot after that is a no-op ls check.
if [ -z "$(ls -A "$PLAYWRIGHT_BROWSERS_PATH" 2>/dev/null)" ]; then
echo "Fetching headless Chromium into $PLAYWRIGHT_BROWSERS_PATH (first boot on this volume)..." >&2
playwright install chromium-headless-shell
fi
#
# Wrapped in a restart loop, not a bare `node ... &`: a bare background
# process that crashes stays dead for good, with nothing to bring it
# back -- turning any single render crash (a not-yet-found jsdom/
# Excalidraw edge case, say) into a silent, permanent whiteboard outage
# that looks exactly like "stuck showing stale content forever" from the
# outside, since routers/common.py's get_or_refresh_whiteboard falls
# back to the last good cached image on every failed refresh rather than
# going blank. The 2s sleep just avoids a hot-crash-loop pegging a core
# if something's wrong at every single startup.
(
while true; do
node ./render-service/server.js
echo "whiteboard render sidecar exited (code $?) -- restarting in 2s" >&2
sleep 2
done
) &
exec uvicorn app.main:app --host 0.0.0.0 --port 8420