ruby-on-railsdockerdocker-composeforeman

why does yarn --watch exit (send SIGTERM)


I have a Docker installation that I would like to start with docker compose up (and not have to run 2 extra ttys ) so I added a Procfile.dev looking like this

web: bin/rails server -p 3000 -b '0.0.0.0'
js: yarn build_js --watch
css: yarn build_css --watch

The output is, however, less than enjoyable

√ mindling % docker compose up
[+] Running 3/0
 ⠿ Container mindling_redis       Running                                                                                                                                     0.0s
 ⠿ Container mindling_db          Running                                                                                                                                     0.0s
 ⠿ Container mindling_mindling_1  Created                                                                                                                                     0.0s
Attaching to mindling_db, mindling_1, mindling_redis
mindling_1      | 19:54:04 web.1  | started with pid 16
mindling_1      | 19:54:04 js.1   | started with pid 19
mindling_1      | 19:54:04 css.1  | started with pid 22
mindling_1      | 19:54:06 css.1  | yarn run v1.22.17
mindling_1      | 19:54:06 js.1   | yarn run v1.22.17
mindling_1      | 19:54:06 js.1   | $ esbuild app/javascript/*.* --bundle --outdir=app/assets/builds --watch
mindling_1      | 19:54:06 css.1  | $ tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css --watch
mindling_1      | 19:54:08 js.1   | Done in 2.02s.
mindling_1      | 19:54:08 js.1   | exited with code 0
mindling_1      | 19:54:08 system | sending SIGTERM to all processes
mindling_1      | 19:54:08 web.1  | terminated by SIGTERM
mindling_1      | 19:54:09 css.1  | terminated by SIGTERM
mindling_1 exited with code 0

I've tried running a Bash in the application container - and calling the Procfile in a tty by itself looks more or less like this:

root@facfb249dc6b:/app# foreman start -f Procfile.dev
20:11:45 web.1  | started with pid 12
20:11:45 js.1   | started with pid 15
20:11:45 css.1  | started with pid 18
20:11:48 css.1  | yarn run v1.22.17
20:11:48 js.1   | yarn run v1.22.17
20:11:48 css.1  | $ tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css --watch
20:11:49 js.1   | $ esbuild app/javascript/*.* --bundle --outdir=app/assets/builds --watch
20:11:50 js.1   | [watch] build finished, watching for changes...
20:11:53 web.1  | => Booting Puma
20:11:53 web.1  | => Rails 7.0.0 application starting in development 
20:11:53 web.1  | => Run `bin/rails server --help` for more startup options
20:11:57 web.1  | Puma starting in single mode...
20:11:57 web.1  | * Puma version: 5.5.2 (ruby 3.0.3-p157) ("Zawgyi")
20:11:57 web.1  | *  Min threads: 5
20:11:57 web.1  | *  Max threads: 5
20:11:57 web.1  | *  Environment: development
20:11:57 web.1  | *          PID: 22
20:11:57 web.1  | * Listening on http://0.0.0.0:3000
20:11:57 web.1  | Use Ctrl-C to stop
20:11:58 css.1  | 
20:11:58 css.1  | Rebuilding...
20:11:59 css.1  | Done in 1066ms.
^C20:13:23 system | SIGINT received, starting shutdown
20:13:23 web.1  | - Gracefully stopping, waiting for requests to finish
20:13:23 web.1  | === puma shutdown: 2021-12-22 20:13:23 +0000 ===
20:13:23 web.1  | - Goodbye!
20:13:23 web.1  | Exiting
20:13:24 system | sending SIGTERM to all processes
20:13:25 web.1  | terminated by SIGINT
20:13:25 js.1   | terminated by SIGINT
20:13:25 css.1  | terminated by SIGINT
root@facfb249dc6b:/app# 

What is going on? It works when doing it 'by hand' but if I let docker-compose rip the processes somehow terminates!?!

I have isolated the issue to the build_css script in package.json (or at least it does keep going if I comment that line in the Procfile.dev)


All the 'dirty linen'

My package.json looks like this

{
...8<...
  "scripts": { 
    "build_js": "esbuild app/javascript/*.* --bundle --outdir=app/assets/builds",
    "build_css": "tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css" 
  }, 
...8<...
}

My containers are exceptionally boring, looking like almost everybody else's:

FROM ruby:3.0.3
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install -y nodejs yarn
WORKDIR /app
COPY src/Gemfile /app/Gemfile
COPY src/Gemfile.lock /app/Gemfile.lock
RUN gem install bundler foreman && bundle install
EXPOSE 3000
ENTRYPOINT [ "entrypoint.sh" ]
version: "3.9"
  db:
    build: mysql
    image: mindling_db
    container_name: mindling_db
    command: [ "--default-authentication-plugin=mysql_native_password" ]
    ports:
      - "3306:3306"
    volumes:
      - ~/src/mysql_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: mindling_development

  mindling:
    platform: linux/x86_64
    build: .
    volumes:
      - ./src:/app
    ports:
      - "3000:3000"
    depends_on:
      - db

and finally my entrypoint.sh

#!/usr/bin/env bash
rm -rf /app/tmp/pids/server.pid
foreman start -f Procfile.dev

Solution

  • Allow me to give credit to they who deserve it!! The correct answer was provided by earlopain in this issue on rails/rails

    It's actually an almost embarrassingly easy fix - once you know it :)

    Add tty: true to your docker-compose.yml - like this

      mindling:
        platform: linux/x86_64
        build: .
        tty: true
        volumes:
          - ./src:/app
        ports:
          - "3000:3000"
        depends_on:
          - db