mirror of
https://github.com/moghtech/komodo.git
synced 2026-07-16 01:59:56 -05:00
[GH-ISSUE #1514] Periphery log retrieval can leave stale docker compose logs processes and saturate dockerd CPU #29932
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @Mevas on GitHub (Jul 5, 2026).
Original GitHub issue: https://github.com/moghtech/komodo/issues/1514
Summary
On a Komodo v2.2.0 Periphery host, stale
docker compose ... logs --tail 100subprocesses lived for days/weeks and caused Docker daemon CPU saturation through many activejson-filelog readers.This looks related to the subprocess timeout /
Pendingkeepalive mechanism discussed in #1392, but the concrete failure mode is different: the hung command is log retrieval, and the blast radius is highdockerdCPU from DockerReadLogs/follow.nextPosgoroutines.Environment
ghcr.io/moghtech/komodo-periphery:2.2.0json-fileWhat happened
The host was stuck at very high CPU. Initial suspicion was container healthchecks / monitoring, but profiling showed the dominant CPU was
dockerd, not Periphery or cAdvisor-style monitoring.Several stale Periphery-descended log commands were still running, for example:
Some of these processes had been alive for about
42 days.After killing the stale log processes,
dockerdCPU dropped immediately from roughly675-700%process CPU to roughly58%process CPU, and host load began falling.Docker daemon evidence
perfondockerdshowed the hot path in Docker json-file log reading:strace -cshowed heavy log file reads:Docker pprof showed many active log reader goroutines:
After killing the stale
docker compose ... logs --tail 100processes, the high-CPU condition stopped.Why I think this is a Komodo/Periphery issue
Current
mainstill appears to shell out for stack log retrieval:The command runner uses
cmd.output().awaitwith no wall-clock timeout:This means a
docker compose logs --tail ...command that hangs can keep its Periphery resolver future alive indefinitely.This seems to be the same architectural mechanism as #1392:
Pendingevery 5 seconds while the request is in progress.Pendingas progress and keeps waiting.kill_on_drop(true)does not help if the resolver future is never dropped.Expected behavior
One-shot log retrieval commands like
docker compose logs --tail 100anddocker logs --tail ...should have a bounded wall-clock timeout. If Docker or the Compose plugin hangs, Periphery should kill the subprocess and return a failed log response instead of keeping the request alive forever.Ideally the timeout should kill the process group, not only the direct child, because
docker composecan spawn subprocesses.Actual behavior
Stale log retrieval subprocesses can survive for days/weeks. In this case, they kept Docker log readers active and caused multi-core
dockerdCPU usage.Suggested fix
A low-risk targeted fix would be to add timeout-aware command helpers and use them for log retrieval endpoints:
GetComposeLogGetComposeLogSearchGetContainerLogGetContainerLogSearchFor example, log retrieval could have a 15-30 second wall-clock timeout, while deploy/build/pull paths keep their existing behavior or get a separate configurable long timeout.
I would avoid a short global timeout on every
run_standard_command/run_shell_commandcall because those helpers are also used for legitimate long-running operations like compose up, pulls, builds, prune operations, and post-deploy hooks.Related issue
Related but not identical: #1392 describes the same no-timeout /
Pendingkeepalive mechanism with a hungdocker compose lssubprocess. This issue is specifically aboutdocker compose logs --tail 100leaving Docker log readers active and saturatingdockerdCPU.@mbecker20 commented on GitHub (Jul 5, 2026):
Do you pass init: true to periphery container? This allows the sub-processes to be properly reaped. Needed on both core and periphery containers.
@Mevas commented on GitHub (Jul 11, 2026):
Yes, checked and I do have
init: truefor both of them: