You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Since Compose v2.39.3, an attached docker compose up never exits when the project is stopped externally (docker compose stop + docker compose down from another process) while one of the containers is in restart backoff (Status=restarting with restart: unless-stopped).
Up to v2.39.2 the attached up exited a few seconds after down completed. From v2.39.3 on it hangs forever, even though all containers are stopped and removed. The behavior is still present in v5.3.1 (latest at the time of writing).
The apparent mechanism, observed via docker events during the stop window:
a container that is stopped while it is in restart backoff emits only stop → destroy events — there is no die event, because no process is running at that moment;
containers that are running normally when stopped emit the full kill → stop → die → destroy sequence;
since v2.39.3 (detect container is restarted #13210), the attached up appears to wait for a die event per container to detect termination, so it waits forever for the container that never emits one.
This matters for supervisors that spawn an attached up as a child process and stop the project externally: the leftover up process keeps holding resources it inherited (in our case, flock file locks on the compose files taken by a wrapper), long after the project is gone.
docker compose -p repro up --remove-orphans --force-recreate & (attached, in background)
Wait until the crasher is in restart backoff: docker inspect repro-crasher-1 --format '{{.State.Status}} {{.RestartCount}}' shows restarting with RestartCount >= 5
From another shell: docker compose -p repro stop -t 5 && docker compose -p repro down -t 5
Observe the backgrounded up process:
v2.39.2 and earlier: exits within a few seconds after down
v2.39.3 and later (incl. v5.0.2, v5.3.1): never exits (waited 120+ s)
Bisect over official release binaries (same engine, same procedure, PASS = up exits / FAIL = up hangs):
version
result
v2.15.1
PASS
v2.26.0
PASS
v2.33.1
PASS
v2.37.3
PASS
v2.38.2
PASS
v2.39.0
PASS
v2.39.1
PASS
v2.39.2
PASS
v2.39.3
FAIL (first bad release)
v2.39.4
FAIL
v5.0.2
FAIL
v5.3.1
FAIL
We also verified on a separate machine (same engine v29.3.0) that swapping only the compose CLI plugin between v5.0.2 and v2.38.2 toggles the hang with an identical docker events sequence, so the regression is in compose, not in the engine.
Compose Version
Docker Compose version v5.0.2
(also reproduced with v2.39.3, v2.39.4, v5.3.1; not reproducible with v2.39.2 and earlier)
Docker Environment
Reproduced on:
- Docker Engine 29.6.2 (amd64, WSL2) — bisect environment
- Docker Engine 29.3.0 (amd64, embedded Linux device) — production environment
Client: docker compose CLI plugin, official release binaries
Anything else?
The first bad release v2.39.3 contains #13210 ("use events to detect container exit"), which matches the observed mechanism (no die event is emitted for a container stopped during restart backoff).
Possibly related: moby/moby#50908 (open) adds a restarting attribute to die events for #13210's event-based detection. However, in this scenario the container emits no die event at all (only stop → destroy), so the attribute alone would not cover this case.
Description
Since Compose v2.39.3, an attached
docker compose upnever exits when the project is stopped externally (docker compose stop+docker compose downfrom another process) while one of the containers is in restart backoff (Status=restartingwithrestart: unless-stopped).Up to v2.39.2 the attached
upexited a few seconds afterdowncompleted. From v2.39.3 on it hangs forever, even though all containers are stopped and removed. The behavior is still present in v5.3.1 (latest at the time of writing).The apparent mechanism, observed via
docker eventsduring the stop window:stop→destroyevents — there is nodieevent, because no process is running at that moment;kill→stop→die→destroysequence;upappears to wait for adieevent per container to detect termination, so it waits forever for the container that never emits one.This matters for supervisors that spawn an attached
upas a child process and stop the project externally: the leftoverupprocess keeps holding resources it inherited (in our case,flockfile locks on the compose files taken by a wrapper), long after the project is gone.Steps To Reproduce
docker-compose.yml:docker compose -p repro up --remove-orphans --force-recreate &(attached, in background)docker inspect repro-crasher-1 --format '{{.State.Status}} {{.RestartCount}}'showsrestartingwith RestartCount >= 5docker compose -p repro stop -t 5 && docker compose -p repro down -t 5upprocess:downBisect over official release binaries (same engine, same procedure, PASS = up exits / FAIL = up hangs):
We also verified on a separate machine (same engine v29.3.0) that swapping only the compose CLI plugin between v5.0.2 and v2.38.2 toggles the hang with an identical
docker eventssequence, so the regression is in compose, not in the engine.Compose Version
Docker Environment
Anything else?
The first bad release v2.39.3 contains #13210 ("use events to detect container exit"), which matches the observed mechanism (no
dieevent is emitted for a container stopped during restart backoff).Possibly related: moby/moby#50908 (open) adds a
restartingattribute todieevents for #13210's event-based detection. However, in this scenario the container emits nodieevent at all (onlystop→destroy), so the attribute alone would not cover this case.