Files
CosmicClash/deploy/cosmic-clash-server
T
Josh Creek c0a1ef94f0 fix(server): force line-buffered stdout so a detached server actually logs
Godot's stdout is fully (block) buffered whenever it isn't attached to
a TTY -- true of every real deployment path this repo documents:
'docker run -d' (Docker's log driver presents a pipe), a plain
'docker run' without -d, and systemd's journal capture (also a pipe).
Confirmed directly, not from the existing gotcha note alone: a real
'docker run -d' container sat for 20+ seconds with 'docker logs'
showing nothing at all -- not even the startup line -- while the
process was confirmed alive and running (ps aux inside the container).
'docker stop' then killed it via SIGTERM (Godot has no SIGTERM hook)
without ever flushing that buffered output, losing it permanently
rather than merely delaying it.

This affects the already-shipped community server path today, not
just the not-yet-built Agones fleet path multiplayer-next.md's task
8.28 gotcha originally flagged this for -- SERVER.md's Docker AND
native-systemd instructions both route through this exact launcher
script, and journald's capture has the same non-TTY-pipe buffering
problem docker logs does.

Wrap the exec in 'stdbuf -oL -eL' (LD_PRELOAD-based line buffering,
touches no binary) when available, falling back to the unwrapped exec
otherwise so a minimal image without GNU coreutils still starts.
Re-verified the same failing scenario against the actual launcher
script in a real image: the startup line now appears within 3s of a
genuinely detached 'docker run -d'. Re-ran the full make verify-phase6
gate end to end afterward to confirm no regression: both arenas
rotated, both clients observed both goals, clean teardown.
2026-09-01 13:50:09 +01:00

24 lines
1.4 KiB
Bash

#!/usr/bin/env sh
# Native and container launcher for the dedicated export. Its server boot scene
# is baked into the dedicated artifact during the Docker export stage.
set -eu
# Godot's stdout is fully (block) buffered rather than line-buffered whenever
# it isn't attached to a TTY -- true of every real deployment of this script:
# `docker run -d` (Docker's log driver presents a pipe, not a TTY), a plain
# `docker run` even without -d, and systemd's journal capture (also a pipe).
# Verified directly: a `docker run -d` container sat for 20+ seconds with
# `docker logs` showing nothing at all, including the startup line, while the
# process was confirmed alive and running; docker stop's SIGTERM (Godot has
# no SIGTERM hook, see SERVER.md) then killed it without ever flushing that
# buffered output, losing it permanently rather than merely delaying it.
# `stdbuf -oL -eL` forces line buffering via LD_PRELOAD without touching the
# binary; re-verified the same scenario then shows the startup line within
# 3s. Fall back to running unwrapped if stdbuf isn't available (e.g. a
# minimal image without GNU coreutils) rather than failing to start at all --
# a server with delayed logs is still far better than no server.
if command -v stdbuf >/dev/null 2>&1; then
exec stdbuf -oL -eL "$(dirname "$0")/CosmicClashServer.x86_64" --headless -- "$@"
fi
exec "$(dirname "$0")/CosmicClashServer.x86_64" --headless -- "$@"