Skip to content

Commit 563bb99

Browse files
Adds Puma :delayed_stop plugin (#36)
Installs the :delayed_stop plugin to avoid "connection closed" errors during Docker Swarm deployments.
1 parent ea1a4ea commit 563bb99

File tree

10 files changed

+102
-35
lines changed

10 files changed

+102
-35
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,10 @@ jobs:
130130

131131
- name: Setup the stack
132132
run: |
133-
docker run --rm "${DOCKER_APP_IMAGE}" rails secret > /tmp/secret_key_base
133+
docker run --quiet --rm "${DOCKER_APP_IMAGE}" rails secret > /tmp/secret_key_base
134134
docker compose build --quiet
135135
docker compose pull --quiet
136136
docker compose up --wait
137-
docker compose exec -e RAILS_ENV=test app rails db:await db:setup assets:precompile
138137
docker compose exec -u root app chown -R altmedia:altmedia artifacts
139138
140139
- name: Run RSpec
@@ -162,7 +161,7 @@ jobs:
162161
- name: Copy out artifacts
163162
if: ${{ always() }}
164163
run: |
165-
docker compose cp app:/opt/app/artifacts ./
164+
docker compose cp app:/opt/app/artifacts ./ || mkdir artifacts
166165
docker compose logs > artifacts/docker-compose-services.log
167166
docker compose config > artifacts/docker-compose.merged.yml
168167

CONTRIBUTING.md

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ own mistakes. 🙂
5858

5959
- [Docker Desktop](https://www.docker.com/products/docker-desktop)
6060

61-
Windows developers should also consider installing the
62-
[Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/).
61+
Windows developers should also consider installing the
62+
[Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/).
6363
See “[Docker Desktop WSL 2 backend](https://docs.docker.com/docker-for-windows/wsl/)
6464
for instructions on integrating Docker Desktop with WSL.
6565

@@ -112,12 +112,24 @@ above, that service will fail to start.
112112

113113
Navigate to [`http://localhost:3000/home`](http://localhost:3000/home).
114114

115-
**Note:** On first run, the database will not exist and assets (javascript/css) will not be precompiled.
116-
To set up the database and precompile the assets, you can use `docker-compose exec` to run the relevant
117-
Rake tasks in the application container.
115+
**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:
118116

119117
```sh
120-
docker compose exec -u root app rails db:setup assets:precompile
118+
docker compose run --rm init
119+
```
120+
121+
You can, equivalently, simply exec commands on the running `app` container:
122+
123+
```sh
124+
docker compose exec app rails …
125+
docker compose run --rm app rails … # similar, but in a one-off container
126+
```
127+
128+
If the stack's many `depends_on` declarations are slowing you down, use Compose's `--no-deps` flag to skip loading dependencies:
129+
130+
```sh
131+
docker compose up --no-deps app
132+
docker compose run --rm --no-deps app …
121133
```
122134

123135
#### 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
170182
### Requirements
171183

172184
- Ruby (see [`.ruby-version`](.ruby-version) for the required version
173-
- recommended: a Ruby version manager such as [RVM](https://rvm.io/),
174-
[rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby),
185+
- recommended: a Ruby version manager such as [RVM](https://rvm.io/),
186+
[rbenv](https://github.com/rbenv/rbenv), [chruby](https://github.com/postmodern/chruby),
175187
or [asdf-ruby](https://github.com/asdf-vm/asdf-ruby).
176188
- [node.js](https://nodejs.org/en/)
177189
- 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/).
199211
DATABASE_URL='postgres://<user>:<password>@<host>/<database-name>' rails s
200212
```
201213

202-
**Note:** Placing `DATABASE_URL` and other environment variables in a
214+
**Note:** Placing `DATABASE_URL` and other environment variables in a
203215
[`.env` file](https://github.com/bkeepers/dotenv) can simplify development.
204216

205217
#### Accessing the server

Dockerfile

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,6 @@ RUN corepack enable \
5353
&& corepack prepare yarn@stable --activate \
5454
&& yarn -v
5555

56-
# Remove packages we only needed as part of the Node.js / Yarn repository
57-
# setup and installation -- note that the Node.js setup scripts installs
58-
# a full version of Python, but at runtime we only need a minimal version
59-
60-
RUN apt-get autoremove --purge -y curl
61-
6256
# ------------------------------------------------------------
6357
# Run configuration
6458

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ gem 'omniauth-rails_csrf_protection', '~> 1.0'
3131
gem 'pg', '~> 1.2'
3232
gem 'prawn', '~> 2.4'
3333
gem 'puma', '~> 7.2'
34+
gem 'puma-plugin-delayed_stop', '~> 0.1.2'
3435
gem 'rails', '~> 8.0.4'
3536
gem 'recaptcha', '~> 4.13'
3637
gem 'sassc-rails'

Gemfile.lock

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,8 @@ GEM
315315
public_suffix (7.0.2)
316316
puma (7.2.0)
317317
nio4r (~> 2.0)
318+
puma-plugin-delayed_stop (0.1.2)
319+
puma (>= 5.0, < 8)
318320
raabro (1.4.0)
319321
racc (1.8.1)
320322
rack (3.2.5)
@@ -553,6 +555,7 @@ DEPENDENCIES
553555
pg (~> 1.2)
554556
prawn (~> 2.4)
555557
puma (~> 7.2)
558+
puma-plugin-delayed_stop (~> 0.1.2)
556559
rails (~> 8.0.4)
557560
recaptcha (~> 4.13)
558561
roo (~> 2.8)

config/puma.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,5 @@
3838
# Specify the PID file. Defaults to tmp/pids/server.pid in development.
3939
# In other environments, only set the PID file if requested.
4040
pidfile ENV['PIDFILE'] if ENV['PIDFILE']
41+
42+
plugin :delayed_stop

config/routes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
get 'admin', to: 'home#admin'
55
get 'health', to: 'ok_computer/ok_computer#index', defaults: { format: :json }
6+
get 'health/:check', to: 'ok_computer/ok_computer#show', defaults: { format: :json }
67
get 'home', to: 'home#index'
78
get 'build_info', to: 'home#build_info'
89

docker-compose.ci.yml

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,40 @@
11
services:
2-
db:
3-
volumes: !reset
4-
52
app:
63
build: !reset
74
environment:
85
- CAPYBARA_SAVE_PATH=/opt/app/artifacts
96
image: ${DOCKER_APP_IMAGE}
107
depends_on:
11-
- selenium
8+
selenium:
9+
condition: service_started
10+
required: false
1211
volumes: !override
1312
- artifacts:/opt/app/artifacts
1413
secrets:
1514
- SECRET_KEY_BASE
16-
ports: !reset
1715

18-
worker:
16+
db:
17+
volumes: !reset
18+
19+
dbeaver: !reset
20+
21+
init:
1922
build: !reset
2023
image: ${DOCKER_APP_IMAGE}
24+
secrets:
25+
- SECRET_KEY_BASE
2126
volumes: !reset
2227

2328
selenium:
2429
volumes: !override
2530
- artifacts:/build
2631

27-
dbeaver: !reset
32+
worker:
33+
build: !reset
34+
image: ${DOCKER_APP_IMAGE}
35+
secrets:
36+
- SECRET_KEY_BASE
37+
volumes: !reset
2838

2939
secrets:
3040
SECRET_KEY_BASE:

docker-compose.yml

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,20 @@ services:
44
context: .
55
target: development
66
depends_on:
7-
db:
8-
condition: service_started
7+
init:
8+
condition: service_completed_successfully
9+
required: false
910
worker:
10-
condition: service_started
11-
selenium:
12-
condition: service_started
11+
condition: service_healthy
12+
required: false
13+
environment:
14+
- PUMA_DELAYED_STOP_DRAIN_SECONDS=1
15+
healthcheck:
16+
test: curl -sf http://localhost:3000/health/default
17+
interval: 15s
18+
timeout: 1s
19+
retries: 3
20+
start_period: 30s
1321
init: true
1422
networks:
1523
default:
@@ -20,19 +28,36 @@ services:
2028
ports:
2129
- 3000:3000
2230
restart: always
31+
stop_grace_period: 30s
32+
stop_signal: QUIT
2333

2434
worker:
2535
<<: *services-app
2636
command: good_job start
2737
depends_on:
28-
- db
29-
- selenium
38+
init:
39+
condition: service_completed_successfully
40+
required: false
41+
environment:
42+
- GOOD_JOB_PROBE_PORT=7001
43+
healthcheck:
44+
test: curl -sf http://localhost:7001/status/started
45+
interval: 1m
46+
timeout: 5s
47+
retries: 5
48+
start_period: 30s
3049
ports: []
3150

3251
db:
3352
environment:
3453
POSTGRES_PASSWORD: root
3554
POSTGRES_USER: root
55+
healthcheck:
56+
test: pg_isready -U root
57+
interval: 10s
58+
timeout: 5s
59+
retries: 5
60+
start_period: 30s
3661
image: postgres:16
3762
networks:
3863
default:
@@ -44,6 +69,24 @@ services:
4469
volumes:
4570
- ./:/build:rw
4671

72+
init:
73+
<<: *services-app
74+
command:
75+
- sh
76+
- -c
77+
- |
78+
set -e
79+
rails assets:precompile db:await db:setup
80+
RAILS_ENV=test rails db:setup
81+
depends_on:
82+
db:
83+
condition: service_healthy
84+
required: false
85+
healthcheck:
86+
disable: true
87+
ports: []
88+
restart: on-failure:5
89+
4790
selenium:
4891
image: selenium/standalone-chromium
4992
networks:
@@ -61,7 +104,9 @@ services:
61104
image: dbeaver/cloudbeaver:latest
62105
container_name: dbeaver
63106
depends_on:
64-
- db
107+
db:
108+
condition: service_healthy
109+
required: false
65110
restart: always
66111
ports:
67112
- '8080:8978'

spec/request/okcomputer_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
stub_request(:get, Rails.application.config.paypal_payflow_url).to_return(status: 200)
1212
end
1313

14-
it 'is mounted at /okcomputer' do
15-
get '/okcomputer'
14+
it 'is mounted at /health' do
15+
get '/health'
1616
expect(response).to have_http_status :ok
1717
end
1818

0 commit comments

Comments
 (0)