gotchabashdockerMajor
Orphaned `docker exec … createdb` clients can spin for days and keep the Postgres container at several cores of CPU
Viewed 0 times
Seen with Docker Desktop on macOS 15 and a Postgres 15 Supabase local stack; the docker exec lifetime behavior is general.
createdbdocker execorphan processpostmaster CPUcontext switchesPPID 0throwaway databaseload average
Error Messages
Problem
The load average stayed at ~14 on 8 cores for more than a day.
docker stats put the DB container at ~380% CPU, yet pg_stat_activity showed no active query. Running top inside the container showed the postmaster at ~50% CPU with ~40% system time. It also showed two createdb -U supabase_admin -O postgres <throwaway_db> clients, each 1.5 days old, with PPID 0 and over 2 hours of CPU time. Their target databases did not exist. Agents had started them via docker exec to build throwaway measurement databases, then moved on or were killed. The exec sessions were abandoned, but the clients kept running.Solution
- Look for stray clients inside the container, not only on the host. Orphans have PPID 0 and a long ETIME:
docker exec <db> ps -eo pid,ppid,etime,time,args | grep -E 'createdb|dropdb|psql'. - Confirm read-only that they are busy. In
/proc/<pid>/status, voluntary_ctxt_switches grows by hundreds per second, for each client and for the postmaster. - Kill them inside the container:
docker exec <db> kill <pid> <pid>. Results here: container CPU dropped from ~384% to ~4% at once, the Docker VM from ~370% to ~50%, and the host 1-minute load from ~14 to ~4. - Prevent it in agent-run scripts:
- put a hard timeout on every createdb/dropdb/psql run through docker exec;
- never run createdb while template1 has other connections;
- end every run by checking that none of its processes remain, in the container and on the host.
Why
docker exec does not tie the life of the process in the container to the host-side client. When the host side dies, the container process is reparented to PID 0 and keeps running. A libpq client stuck in a loop with the server wakes the postmaster on every iteration. On Docker Desktop, that kernel work is billed to the whole VM. Host-side ps then shows only com.apple.Virtualization.VirtualMachine at several hundred percent, with no hint of the cause.Gotchas
- pg_stat_activity shows nothing: the stuck clients hold no backend, so DB-side monitoring misses them
- Host-side ps only shows the VM process; the culprit is only visible with ps/top inside the container
- Killing them freed more CPU than closing the browser, which was the first suspect
Code Snippets
Find orphaned clients inside the DB container and measure how busy they are
docker exec db ps -eo pid,ppid,etime,time,args | grep -E 'createdb|dropdb|psql' | grep -v grep
for p in <pid>; do docker exec db grep ctxt /proc/$p/status; done; sleep 5; for p in <pid>; do docker exec db grep ctxt /proc/$p/status; doneContext
During long unattended runs where automated agents create and drop throwaway Postgres databases through
docker exec against a local Postgres container (Supabase-style stack on Docker Desktop for macOS).Revisions (0)
No revisions yet.