Move DB initialization scripts for postgres and redis into service files.

This resolves a race condition with unconfigured images attempting to bring up
DBs for the first time. This does not affect fully bootstrapped images.

Currently, all jobs start at boot - this includes postgres.

Issue with the current is - postgres starts and adds the corresponding .s/.pid
files to /var/run/postgres.

Simultaneously, the unicorn job gets started, checks to see if postgres is
running (it is already at this point from boot), and runs install_postgres.

Inside the install_postgres script, we mount the shared postgres folder and
remove .s/.pid files -- after postgres has already been started. In this case,
we remove the (in-use) .s and .pid files.

Subsequent unicorn tasks fail, erroring out the service and forcing it into
a restart loop. Since postgres never restarts, it never regenerates the .s/.pid
files, and unicorn can never run successfully.

This proposal moves install_postgres into the postgres job file, eliminating the
race condition. Since they are part of the same service, install_postgres will
always run before starting postgres - it will no longer be able to remove valid
.s and .pid files.

Redis has a similar race condition with the creation of its data folder. This
isn't as disastrous as the redis service restarts until the folder exists from
unicorn run, but it provides better reasoning about the running services.

Add early exit from unicorn boot scripts to properly retry migrate as well.

Use pg_isready to check if pg is ready directly in create_db.
Merge the ready check into create_db.

Run create_db in a subshell on postgres job start, rather than in unicorn script.

remove postgres-config call
This commit is contained in:
Jeff Wong 2025-05-17 14:41:48 -07:00
parent 64f31dbbe3
commit 136aefe49d
No known key found for this signature in database
GPG Key ID: D4EEB78E484F8A83
3 changed files with 17 additions and 12 deletions

View File

@ -16,10 +16,6 @@ hooks:
filename: /etc/service/unicorn/run
from: "# postgres"
to: |
if [ -f /root/install_postgres ]; then
/root/install_postgres
rm /root/install_postgres
fi
sv start postgres || exit 1
run:
@ -29,6 +25,13 @@ run:
contents: |
#!/bin/sh
exec 2>&1
if [ -f /root/install_postgres ]; then
/root/install_postgres
rm /root/install_postgres
fi
if [ "$CREATE_DB_ON_BOOT" = "1" ]; then
/usr/local/bin/create_db&
fi
HOME=/var/lib/postgresql USER=postgres exec thpoff chpst -u postgres:postgres:ssl-cert -U postgres:postgres:ssl-cert /usr/lib/postgresql/15/bin/postmaster -D /etc/postgresql/15/main
- file:
@ -242,6 +245,11 @@ run:
chmod: +x
contents: |
#!/bin/bash
# wait for postgres to start up...
for i in {1..5}; do
su postgres -c 'pg_isready -q' && break
sleep 1
done
su postgres -c 'createdb $db_name' || true
su postgres -c 'psql $db_name -c "create user $db_user;"' || true
su postgres -c 'psql $db_name -c "grant all privileges on database $db_name to $db_user;"' || true
@ -278,7 +286,5 @@ run:
tag: db
hook: postgres
cmd:
# give db a few secs to start up
- "sleep 5"
- /usr/local/bin/create_db
- "echo postgres installed!"

View File

@ -9,6 +9,9 @@ run:
contents: |
#!/bin/sh
exec 2>&1
if [ ! -d /shared/redis_data ]; then
install -d -m 0755 -o redis -g redis /shared/redis_data
fi
exec thpoff chpst -u redis -U redis /usr/bin/redis-server /etc/redis/redis.conf
- file:
path: /etc/service/redis/log/run
@ -88,7 +91,4 @@ hooks:
filename: /etc/service/unicorn/run
from: "# redis"
to: |
if [ ! -d /shared/redis_data ]; then
install -d -m 0755 -o redis -g redis /shared/redis_data
fi
sv start redis || exit 1

View File

@ -61,9 +61,8 @@ run:
if [[ -z "$PRECOMPILE_ON_BOOT" ]]; then
PRECOMPILE_ON_BOOT=1
fi
if [ -f /usr/local/bin/create_db ] && [ "$CREATE_DB_ON_BOOT" = "1" ]; then /usr/local/bin/create_db; fi;
if [ "$MIGRATE_ON_BOOT" = "1" ]; then su discourse -c 'bundle exec rake db:migrate'; fi
if [ "$PRECOMPILE_ON_BOOT" = "1" ]; then SKIP_EMBER_CLI_COMPILE=1 su discourse -c 'bundle exec rake assets:precompile'; fi
if [ "$MIGRATE_ON_BOOT" = "1" ]; then su discourse -c 'bundle exec rake db:migrate' || exit 1; fi
if [ "$PRECOMPILE_ON_BOOT" = "1" ]; then SKIP_EMBER_CLI_COMPILE=1 su discourse -c 'bundle exec rake assets:precompile' || exit 1; fi
LD_PRELOAD=$RUBY_ALLOCATOR HOME=/home/discourse USER=discourse exec thpoff chpst -u discourse:www-data -U discourse:www-data bundle exec config/unicorn_launcher -E production -c config/unicorn.conf.rb
- file: