Skip to content

[BUG] Docker compose up --watch stopped working #13161

Description

@tamis-laan

Description

I upgraded to the latest version of docker compose and now I get the following:

              ⦿ Syncing service "app" after 1 changes were detected
app-1         | INFO:uvicorn.error: Shutting down
app-1         | INFO:uvicorn.error: Waiting for application shutdown.
app-1         | INFO:uvicorn.error: Application shutdown complete.
app-1         | INFO:uvicorn.error: Finished server process [1]
              ⦿ service(s) ["app"] restarted
app-1 exited with code 0

I have sync+restart in my watch configuration for app. On file change the app is properly restarted but the logs and not printed any more. I know this because docker compose logs -f app will show logs properly.

Now this problem has come up in the past and was fixed, but I think someone reverted things or reimplemented the same mistake.

I'm on macos 14.7.6 (23H626) using the following versions through homebrew:

colima 0.8.4
docker 28.3.3
docker-buildx 0.26.1
docker-compose 2.39.2

Activity

  1. mateuspiresl commented on Aug 28, 2025

    @mateuspiresl

    I've been experiencing similar behavior since last week.

    Since then, restarting a container stops displaying the service logs in the existing compose up process output.

    I've heard colleagues experiencing the same and also seeing duplicated log lines. I couldn't reproduce that last behavior, though.

  2. coredumperror commented on Aug 28, 2025

    @coredumperror

    Same thing happens to me on Docker Desktop 4.45.0 with Docker Compose v2.39.2-desktop.1.

    It does not happen with Docker Desktop 4.44.3 and Docker Compose v2.39.1-desktop.1, so it seems to have been introduced in the latest patch release of Compose (which is the version that fixed the log duplication... so I bet that fix is probably the cause).

    As an additional note, pressing Ctrl-C on a docker compose up --watch with v2.39.2-desktop.1 immediately kills the app, rather than starting the container shutdown sequence, which is what it did before. Possibly related?

  3. ulyssessouza commented on Aug 29, 2025

    @ulyssessouza
    Contributor

    @tamis-laan Could you please provide a minimalistic version of your compose.yaml so that I can reproduce the issue?

  4. self-assigned this
    on Aug 29, 2025
  5. ndeloof commented on Aug 29, 2025

    @ndeloof
    Contributor

    I was not able to reproduce with a minimal example:

    services:
      app:
        build:
          dockerfile_inline: |
            FROM alpine:latest
            CMD ping localhost
        develop:
          watch:
            - path: .
              target: /tmp
              action: sync+restart

    @coredumperror can't reproduce either:

    $ docker compose up --watch
    [+] Running 1/1
     ✔ Container truc-app-1  Running                                                                                                                                                                                          0.0s 
            ⦿ Watch enabled
    Attaching to app-1
    app-1   | 64 bytes from ::1: seq=26 ttl=64 time=0.281 ms
    app-1   | 64 bytes from ::1: seq=27 ttl=64 time=0.206 ms
    Gracefully Stopping... press Ctrl+C again to force
     Container truc-app-1  Stopping
    app-1   | 64 bytes from ::1: seq=28 ttl=64 time=0.099 ms
    ...
    Container truc-app-1  Stopped
    
  6. coredumperror commented on Aug 29, 2025

    @coredumperror

    Could it be related to the fact that I have two containers running the same image, with the same files attached to sync+restart rules? They use different env vars to replicate the two different servers that we run the same software on.

    I also have a mysql:8.4, elasticsearch:7.10.1, redis/redis-stack:latest, and axllent/mailpit container in my docker-compose.yml file.

    Here's a somewhat stripped down and anonymized version version of our docker-compose.yml for the two custom services:

      multitenant:
        image: sites:latest
        container_name: multitenant
        hostname: multitenant
        networks:
          mtnet:
            ipv4_address: 172.20.0.10
        cap_add:
          # We need SYS_PTRACE to run py-spy to profile our tests
          - SYS_PTRACE
        ports:
          # Map port 443 on the host to port 8443 in the container, allowing access via normal https:// urls.
          - "443:8443"
          # The port that the debug server for sites listens on, for VS Code to connect to it in "connect" mode.
          - "6789:6789"
        env_file:
          - /etc/context.d/multitenant.env
          - /etc/context.d/aws_sso_credentials.env
        depends_on:
          - mysql
          - elastic
          - redis
        extra_hosts:
          # Maps DNS hostnames to the actual IPs of the appropriate containers. Required for cross-container syncs.
          - "main.localhost:172.20.0.11"
          - "pma.localhost:172.20.0.10"
        build:
          context: .
          tags:
            - sites:6.13.5
            - sites:latest
        develop:
          # Create a `watch` configuration to update the app's code in the image as it changes on the host.
          watch:
            # Sync the working directory with the /app directory in the container.
            - action: sync
              path: .
              target: /app
              ignore:
                # Ignore all migrations directories, because those are controlled by the volume mounts below.
                - "**/migrations"
            # Optional: Automatically detect changes to config files and restart the service to pick them up.
            # This is especially nice because you don't have to rebuild the image to activate the changes.
            - action: sync+restart
              path: ./etc/nginx/nginx.conf
              target: /app/etc/nginx/nginx.conf
              path: ./etc/supervisord.conf
              target: /app/etc/supervisord.conf
            # Optional: Automatically rebuild the image (and restart the service) upon any change to these files.
            - action: rebuild
              path: ./uv.lock
            - action: rebuild
              path: ./.dockerignore
            - action: rebuild
              path: ./Dockerfile
        volumes:
          # We use volume mounts for migrations directories so that `manage.py makemigrations` can write to the repo.
          - ./multitenant/api/migrations:/app/multitenant/api/migrations
          - ./multitenant/core/migrations:/app/multitenant/core/migrations
          - ./multitenant/redirects/migrations:/app/multitenant/redirects/migrations
    
      multitenant_www:
        image: sites:latest
        container_name: multitenant_www
        hostname: multitenant_www
        networks:
          mtnet:
            ipv4_address: 172.20.0.11
        cap_add:
          # We need SYS_PTRACE to run py-spy to profile our tests
          - SYS_PTRACE
        ports:
          # Map port 8443 on the host to port 8443 in the container, allowing access at https://main.localhost:8443
          - "8443:8443"
          # The port that the debug server for www listens on, for VS Code to connect to it in "connect" mode.
          - "6790:6790"
        env_file:
          - /etc/context.d/multitenant_www.env
          - /etc/context.d/aws_sso_credentials.env
        depends_on:
          - mysql
          - elastic
          - redis
        build:
          context: .
          tags:
            - sites:6.13.5
            - sites:latest
        develop:
          # Create a `watch` configuration to update the app's code in the image as it changes on the host.
          watch:
            # Sync the working directory with the /app directory in the container.
            - action: sync
              path: .
              target: /app
              ignore:
                # Ignore all migrations directories, because those are controlled by the volume mounts below.
                - "**/migrations"
            # Optional: Automatically detect changes to config files and restart the service to pick them up.
            # This is especially nice because you don't have to rebuild the image to activate the changes.
            - action: sync+restart
              path: ./etc/nginx/nginx.conf
              target: /app/etc/nginx/nginx.conf
            - action: sync+restart
              path: ./etc/supervisord.conf
              target: /app/etc/supervisord.conf
            # Optional: Automatically rebuild the image (and restart the service) upon any change to these files.
            - action: rebuild
              path: ./uv.lock
            - action: rebuild
              path: ./.dockerignore
            - action: rebuild
              path: ./Dockerfile
        volumes:
          # We use volume mounts for migrations directories so that `manage.py makemigrations` can write to the repo.
          - ./multitenant/api/migrations:/app/multitenant/api/migrations
          - ./multitenant/core/migrations:/app/multitenant/core/migrations
          - ./multitenant/redirects/migrations:/app/multitenant/redirects/migrations
    
  7. ndeloof commented on Sep 3, 2025

    @ndeloof
    Contributor

    @coredumperror I can reproduce this issue using a compose that has twice the same watch config set. Investigating ...

    services:
      web:
        image: alpine
        command: ping localhost
        develop:
          watch:
            - path: .
              target: /foo
              action: sync+restart
      webZ:
        image: alpine
        command: ping localhost
        develop:
          watch:
            - path: .
              target: /foo
              action: sync+restart
  8. tamis-laan commented on Sep 3, 2025

    @tamis-laan
    Author

    @ndeloof I got the following with your setup. If I add a file or change a file it syncs but there is no restart. And then things crash I guess?

    services:
      app:
        build:
          dockerfile_inline: |
            FROM alpine:latest
            CMD ping localhost
        develop:
          watch:
            - path: .
              target: /tmp
              action: sync+restart
    
    > docker compose up --watch
    [+] Running 1/1
     ✔ Container test-app-1  Running                                                                                                     0.0s
            ⦿ Watch enabled
    Attaching to app-1
    app-1   | 64 bytes from ::1: seq=7 ttl=64 time=0.187 ms
    app-1   | 64 bytes from ::1: seq=8 ttl=64 time=0.055 ms
    app-1   | 64 bytes from ::1: seq=9 ttl=64 time=0.164 ms
    app-1   | 64 bytes from ::1: seq=10 ttl=64 time=0.230 ms
    app-1   | 64 bytes from ::1: seq=11 ttl=64 time=0.138 ms
            ⦿ Syncing service "app" after 1 changes were detected
    app-1   | 64 bytes from ::1: seq=12 ttl=64 time=0.183 ms
    app-1   | 64 bytes from ::1: seq=13 ttl=64 time=0.175 ms
    app-1   | 64 bytes from ::1: seq=14 ttl=64 time=0.161 ms
    app-1   | 64 bytes from ::1: seq=15 ttl=64 time=0.136 ms
    app-1   | 64 bytes from ::1: seq=16 ttl=64 time=0.246 ms
    app-1   | 64 bytes from ::1: seq=17 ttl=64 time=0.174 ms
    app-1   | 64 bytes from ::1: seq=18 ttl=64 time=0.092 ms
    app-1   | 64 bytes from ::1: seq=19 ttl=64 time=0.131 ms
    app-1   | 64 bytes from ::1: seq=20 ttl=64 time=0.055 ms
    app-1   | 64 bytes from ::1: seq=21 ttl=64 time=0.292 ms
    WARN[0014] Error handling changed files: Post "http://%2FUsers%2FQXZ62ES%2F.config%2Fcolima%2Fdefault%2Fdocker.sock/v1.51/containers/71e67d7af6649c085feeaf118ef6bdce764e27adebd14c3991dbf4269d75ec75/restart": context canceled
            ⦿ Watch disabled
    
  9. tamis-laan commented on Sep 3, 2025

    @tamis-laan
    Author

    @coredumperror I can reproduce this issue using a compose that has twice the same watch config set. Investigating ...

    services:
    web:
    image: alpine
    command: ping localhost
    develop:
    watch:
    - path: .
    target: /foo
    action: sync+restart
    webZ:
    image: alpine
    command: ping localhost
    develop:
    watch:
    - path: .
    target: /foo
    action: sync+restart

    Even with a single develop watch things don't work for me I get:

    app-1         | INFO:     Application startup complete.
    app-1         | INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
    app-1         | INFO:     127.0.0.1:59714 - "GET /healthz HTTP/1.1" 200 OK
                  ⦿ Syncing service "app" after 1 changes were detected
    app-1         | INFO:     Shutting down
    app-1         | INFO:     Waiting for application shutdown.
    app-1         | INFO:     Application shutdown complete.
    app-1         | INFO:     Finished server process [1]
                  ⦿ service(s) ["app"] restarted
    app-1 exited with code 0
                  ⦿ Syncing service "app" after 1 changes were detected
                  ⦿ service(s) ["app"] restarted
    app-1 exited with code 0
                  ⦿ Syncing service "app" after 1 changes were detected
                  ⦿ service(s) ["app"] restarted
    app-1 exited with code 0
    

    Sadly I can't share any code. All this started with an update a few weeks ago for me at least.

  10. ndeloof commented on Sep 4, 2025

    @ndeloof
    Contributor

    @tamis-laan can you give #13199 a try ? (binaries available on https://github.com/docker/compose/actions/runs/17436810592 - artifacts section)

  11. tamis-laan commented on Sep 4, 2025

    @tamis-laan
    Author

    @ndeloof

    This one docker~compose~GAI9YG.dockerbuild.zip?

    Can't unzip it:

    > unzip docker~compose~GAI9YG.dockerbuild.zip 
    Archive:  docker~compose~GAI9YG.dockerbuild.zip
      End-of-central-directory signature not found.  Either this file is not
      a zipfile, or it constitutes one disk of a multi-part archive.  In the
      latter case the central directory and zipfile comment will be found on
      the last disk(s) of this archive.
    unzip:  cannot find zipfile directory in one of docker~compose~GAI9YG.dockerbuild.zip or
            docker~compose~GAI9YG.dockerbuild.zip.zip, and cannot find docker~compose~GAI9YG.dockerbuild.zip.ZIP, period.
    
  12. ndeloof commented on Sep 4, 2025

    @ndeloof
    Contributor
    Image
  13. tamis-laan commented on Sep 7, 2025

    @tamis-laan
    Author

    @ndeloof

    Hm... I tried this but I'm working on a company laptop that is closed off pretty tight and I'm not allowed to share code either 😢

    I would be happy to do a video call though so you can see directly what is going on and see if we can debug it on the spot?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions