diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dd11098d..562ce942 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -130,11 +130,10 @@ jobs: - name: Setup the stack run: | - docker run --rm "${DOCKER_APP_IMAGE}" rails secret > /tmp/secret_key_base + docker run --quiet --rm "${DOCKER_APP_IMAGE}" rails secret > /tmp/secret_key_base docker compose build --quiet docker compose pull --quiet docker compose up --wait - docker compose exec -e RAILS_ENV=test app rails db:await db:setup assets:precompile docker compose exec -u root app chown -R altmedia:altmedia artifacts - name: Run RSpec @@ -162,7 +161,7 @@ jobs: - name: Copy out artifacts if: ${{ always() }} run: | - docker compose cp app:/opt/app/artifacts ./ + docker compose cp app:/opt/app/artifacts ./ || mkdir artifacts docker compose logs > artifacts/docker-compose-services.log docker compose config > artifacts/docker-compose.merged.yml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 91d7bdd7..3e9a247f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -58,8 +58,8 @@ own mistakes. 🙂 - [Docker Desktop](https://www.docker.com/products/docker-desktop) -Windows developers should also consider installing the -[Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/). +Windows developers should also consider installing the +[Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/). See “[Docker Desktop WSL 2 backend](https://docs.docker.com/docker-for-windows/wsl/)” for instructions on integrating Docker Desktop with WSL. @@ -112,12 +112,24 @@ above, that service will fail to start. Navigate to [`http://localhost:3000/home`](http://localhost:3000/home). -**Note:** On first run, the database will not exist and assets (javascript/css) will not be precompiled. -To set up the database and precompile the assets, you can use `docker-compose exec` to run the relevant -Rake tasks in the application container. +**Note:** On first run, an `init` service will run to setup the database and compile assets (javascript/css). If necessary you can run it manually via: ```sh -docker compose exec -u root app rails db:setup assets:precompile +docker compose run --rm init +``` + +You can, equivalently, simply exec commands on the running `app` container: + +```sh +docker compose exec app rails … +docker compose run --rm app rails … # similar, but in a one-off container +``` + +If the stack's many `depends_on` declarations are slowing you down, use Compose's `--no-deps` flag to skip loading dependencies: + +```sh +docker compose up --no-deps app +docker compose run --rm --no-deps app … ``` #### Running commands in the application container @@ -170,8 +182,8 @@ Go to the model rb file and temporarily add `Alma::Type::LIBRARY_STAFF` to `ALLO ### Requirements - Ruby (see [`.ruby-version`](.ruby-version) for the required version - - recommended: a Ruby version manager such as [RVM](https://rvm.io/), - [rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby), + - recommended: a Ruby version manager such as [RVM](https://rvm.io/), + [rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby), or [asdf-ruby](https://github.com/asdf-vm/asdf-ruby). - [node.js](https://nodejs.org/en/) - recommended: a Node version manager such as [nvm](https://github.com/nvm-sh/nvm) @@ -199,7 +211,7 @@ Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/). DATABASE_URL='postgres://:@/' rails s ``` -**Note:** Placing `DATABASE_URL` and other environment variables in a +**Note:** Placing `DATABASE_URL` and other environment variables in a [`.env` file](https://github.com/bkeepers/dotenv) can simplify development. #### Accessing the server diff --git a/Dockerfile b/Dockerfile index 57fcc587..6be9d60f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -53,12 +53,6 @@ RUN corepack enable \ && corepack prepare yarn@stable --activate \ && yarn -v -# Remove packages we only needed as part of the Node.js / Yarn repository -# setup and installation -- note that the Node.js setup scripts installs -# a full version of Python, but at runtime we only need a minimal version - -RUN apt-get autoremove --purge -y curl - # ------------------------------------------------------------ # Run configuration diff --git a/Gemfile b/Gemfile index be1cbf10..8e1618e3 100644 --- a/Gemfile +++ b/Gemfile @@ -31,6 +31,7 @@ gem 'omniauth-rails_csrf_protection', '~> 1.0' gem 'pg', '~> 1.2' gem 'prawn', '~> 2.4' gem 'puma', '~> 7.2' +gem 'puma-plugin-delayed_stop', '~> 0.1.2' gem 'rails', '~> 8.0.4' gem 'recaptcha', '~> 4.13' gem 'sassc-rails' diff --git a/Gemfile.lock b/Gemfile.lock index b32989be..d2086ede 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -315,6 +315,8 @@ GEM public_suffix (7.0.2) puma (7.2.0) nio4r (~> 2.0) + puma-plugin-delayed_stop (0.1.2) + puma (>= 5.0, < 8) raabro (1.4.0) racc (1.8.1) rack (3.2.5) @@ -553,6 +555,7 @@ DEPENDENCIES pg (~> 1.2) prawn (~> 2.4) puma (~> 7.2) + puma-plugin-delayed_stop (~> 0.1.2) rails (~> 8.0.4) recaptcha (~> 4.13) roo (~> 2.8) diff --git a/config/puma.rb b/config/puma.rb index af3ba184..f0ef191a 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -38,3 +38,5 @@ # Specify the PID file. Defaults to tmp/pids/server.pid in development. # In other environments, only set the PID file if requested. pidfile ENV['PIDFILE'] if ENV['PIDFILE'] + +plugin :delayed_stop diff --git a/config/routes.rb b/config/routes.rb index 78d41a49..1dd9a272 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,6 +3,7 @@ get 'admin', to: 'home#admin' get 'health', to: 'ok_computer/ok_computer#index', defaults: { format: :json } + get 'health/:check', to: 'ok_computer/ok_computer#show', defaults: { format: :json } get 'home', to: 'home#index' get 'build_info', to: 'home#build_info' diff --git a/docker-compose.ci.yml b/docker-compose.ci.yml index a58e9e6a..467b0f92 100644 --- a/docker-compose.ci.yml +++ b/docker-compose.ci.yml @@ -1,30 +1,40 @@ services: - db: - volumes: !reset - app: build: !reset environment: - CAPYBARA_SAVE_PATH=/opt/app/artifacts image: ${DOCKER_APP_IMAGE} depends_on: - - selenium + selenium: + condition: service_started + required: false volumes: !override - artifacts:/opt/app/artifacts secrets: - SECRET_KEY_BASE - ports: !reset - worker: + db: + volumes: !reset + + dbeaver: !reset + + init: build: !reset image: ${DOCKER_APP_IMAGE} + secrets: + - SECRET_KEY_BASE volumes: !reset selenium: volumes: !override - artifacts:/build - dbeaver: !reset + worker: + build: !reset + image: ${DOCKER_APP_IMAGE} + secrets: + - SECRET_KEY_BASE + volumes: !reset secrets: SECRET_KEY_BASE: diff --git a/docker-compose.yml b/docker-compose.yml index eb239a5a..87d3e905 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,12 +4,20 @@ services: context: . target: development depends_on: - db: - condition: service_started + init: + condition: service_completed_successfully + required: false worker: - condition: service_started - selenium: - condition: service_started + condition: service_healthy + required: false + environment: + - PUMA_DELAYED_STOP_DRAIN_SECONDS=1 + healthcheck: + test: curl -sf http://localhost:3000/health/default + interval: 15s + timeout: 1s + retries: 3 + start_period: 30s init: true networks: default: @@ -20,19 +28,36 @@ services: ports: - 3000:3000 restart: always + stop_grace_period: 30s + stop_signal: QUIT worker: <<: *services-app command: good_job start depends_on: - - db - - selenium + init: + condition: service_completed_successfully + required: false + environment: + - GOOD_JOB_PROBE_PORT=7001 + healthcheck: + test: curl -sf http://localhost:7001/status/started + interval: 1m + timeout: 5s + retries: 5 + start_period: 30s ports: [] db: environment: POSTGRES_PASSWORD: root POSTGRES_USER: root + healthcheck: + test: pg_isready -U root + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s image: postgres:16 networks: default: @@ -44,6 +69,24 @@ services: volumes: - ./:/build:rw + init: + <<: *services-app + command: + - sh + - -c + - | + set -e + rails assets:precompile db:await db:setup + RAILS_ENV=test rails db:setup + depends_on: + db: + condition: service_healthy + required: false + healthcheck: + disable: true + ports: [] + restart: on-failure:5 + selenium: image: selenium/standalone-chromium networks: @@ -61,7 +104,9 @@ services: image: dbeaver/cloudbeaver:latest container_name: dbeaver depends_on: - - db + db: + condition: service_healthy + required: false restart: always ports: - '8080:8978' diff --git a/spec/request/okcomputer_spec.rb b/spec/request/okcomputer_spec.rb index c97aeced..2a8b0e45 100644 --- a/spec/request/okcomputer_spec.rb +++ b/spec/request/okcomputer_spec.rb @@ -11,8 +11,8 @@ stub_request(:get, Rails.application.config.paypal_payflow_url).to_return(status: 200) end - it 'is mounted at /okcomputer' do - get '/okcomputer' + it 'is mounted at /health' do + get '/health' expect(response).to have_http_status :ok end