#DieLog #3 Live stats & Status polling
Picked up where I left off with a working dashboard that could start/stop containers via HTMX, but the status label was static — no way to tell “starting” from “running,” and CPU/RAM usage was still hardcoded placeholder data from servers.json. Today’s session closed both gaps.
Starting vs. running. Turns out docker start marks a container as running in .State.Status almost instantly — the process is alive, but a Minecraft server still needs real time to generate the world and load plugins. Digging into docker inspect showed the missing piece was .State.Health.Status (starting / healthy / unhealthy), which reflects whether the game actually responds on its port. Combining both fields gives an accurate starting → running transition instead of a status that lies for the first 30+ seconds of boot.
Polling instead of guessing. Wrote pollUntilStatus, a goroutine kicked off after a successful docker start/stop call. It checks container status every 5s and writes the result back into the shared server map until it hits the target state, then exits — no wasted background work once the goal is reached. When the target is running, it hands off to a second goroutine, pollStats, which polls docker stats –no-stream every 5s for as long as the server stays up, and quietly stops the moment status flips away from running.
What went wrong (and got fixed). Two real bugs, both classic Go concurrency traps:
A deadlock in pollStats — called Lock() on the mutex, then called Lock() again a few lines later without releasing the first one. Everything just hung. Fixed by splitting reads (RLock) from writes (Lock) into properly scoped, non-overlapping sections.
An HTMX polling storm — the status fragment carried hx-trigger=“load, every 5s” on itself, so every 5-second refresh re-triggered load instantly, turning “every 5 seconds” into “every few milliseconds.” Fix was moving load to the outer placeholder only, leaving every 5s on the fragment that gets swapped in.
Numbers sanity check. docker stats reported ~0.7% CPU / ~10% memory for an idle vanilla server, while the system monitor showed 40–60% CPU and 5GB RAM at the same time. Looked alarming until it became clear those are two different measurements entirely — docker stats is scoped to the one container, the system monitor is the whole machine (browser, editor, Docker daemon, everything). Once isolated, the container numbers checked out fine.
Net result: dashboard now shows live, accurate status and live CPU/RAM bars over HTMX auto-refresh, all backed by two lightweight, self-terminating goroutines instead of one permanent background loop. Also switched from VS Code to Zed mid-session over memory leaks — anecdotally, Zed didn’t break a sweat running alongside the Docker container, something VS Code couldn’t handle before.