From e13f5cad4835d76632f12a18e2a4c9bf9d563dc1 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Sat, 17 May 2025 14:41:48 -0700 Subject: [PATCH 1/6] 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 --- templates/postgres.template.yml | 18 ++++++++++++------ templates/redis.template.yml | 6 +++--- templates/web.template.yml | 5 ++--- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/templates/postgres.template.yml b/templates/postgres.template.yml index 03813c479..69703e639 100644 --- a/templates/postgres.template.yml +++ b/templates/postgres.template.yml @@ -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: @@ -245,6 +248,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 @@ -281,7 +289,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!" diff --git a/templates/redis.template.yml b/templates/redis.template.yml index b8ddd7e83..c9ce7d6dc 100644 --- a/templates/redis.template.yml +++ b/templates/redis.template.yml @@ -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 diff --git a/templates/web.template.yml b/templates/web.template.yml index 920d06350..0bf71ba84 100644 --- a/templates/web.template.yml +++ b/templates/web.template.yml @@ -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: From 1ada3ce13c170eafd98e70043131f0ea3b1b4038 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Mon, 23 Jun 2025 10:14:03 -0700 Subject: [PATCH 2/6] Update DB password if exists Update DB password on boot in 2 container setup from env if exists --- templates/postgres.template.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/templates/postgres.template.yml b/templates/postgres.template.yml index 69703e639..fdfba1cd0 100644 --- a/templates/postgres.template.yml +++ b/templates/postgres.template.yml @@ -266,6 +266,9 @@ run: su postgres -c 'psql $db_name -c "create extension if not exists vector;"' su postgres -c 'psql $db_name -c "alter extension vector update;"' || true sudo -u postgres psql $db_name <<< "update pg_database set encoding = pg_char_to_encoding('UTF8') where datname = '$db_name' AND encoding = pg_char_to_encoding('SQL_ASCII');" || true + if [ ! -z "$DISCOURSE_DB_PASSWORD" ]; then + echo "alter user $db_user with password '$DISCOURSE_DB_PASSWORD';" | su - postgres -c 'psql $db_name' + fi - file: path: /var/lib/postgresql/take-database-backup From 7b9cb857a60029c66a5c1ec1144b8e3d29442554 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Fri, 25 Jul 2025 09:07:41 -0700 Subject: [PATCH 3/6] DEV: always run install on redis_data directory Fixes permissions on the directory if mis-set. --- templates/redis.template.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/templates/redis.template.yml b/templates/redis.template.yml index c9ce7d6dc..12b8cbce6 100644 --- a/templates/redis.template.yml +++ b/templates/redis.template.yml @@ -9,9 +9,7 @@ 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 + install -d -m 0755 -o redis -g redis /shared/redis_data exec thpoff chpst -u redis -U redis /usr/bin/redis-server /etc/redis/redis.conf - file: path: /etc/service/redis/log/run From 7342f26dc5ee6403db0334ad1a86bdce3fa18f9b Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Fri, 25 Jul 2025 13:24:03 -0700 Subject: [PATCH 4/6] Start postgres separately while creating the DB Use pg_ctl with -w start to ensure postgres is started. Allows create_db to run in the foreground on start for CREATE_DB_ON_BOOT. Take inspiration to how docker-library postgres does similar: https://github.com/docker-library/postgres/blob/889f9447cd2dfe21cccfbe9bb7945e3b037e02d8/15/bullseye/docker-entrypoint.sh#L294-L316 --- templates/postgres.template.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/templates/postgres.template.yml b/templates/postgres.template.yml index fdfba1cd0..2dc469610 100644 --- a/templates/postgres.template.yml +++ b/templates/postgres.template.yml @@ -30,7 +30,9 @@ run: rm /root/install_postgres fi if [ "$CREATE_DB_ON_BOOT" = "1" ]; then - /usr/local/bin/create_db& + sudo -E -u postgres /usr/lib/postgresql/15/bin/pg_ctl -D /etc/postgresql/15/main -o "-c listen_addresses='' -p 5432" -w start + /usr/local/bin/create_db + sudo -E -u postgres /usr/lib/postgresql/15/bin/pg_ctl -D /etc/postgresql/15/main -m fast -w stop 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 @@ -248,11 +250,6 @@ 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 @@ -292,5 +289,7 @@ run: tag: db hook: postgres cmd: + # wait for postgres to start up... + - sleep 5 - /usr/local/bin/create_db - "echo postgres installed!" From efe4f2d5d2923348b2f76c0f5a2d565fe2ccbda0 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Fri, 25 Jul 2025 13:29:21 -0700 Subject: [PATCH 5/6] properly revert sleep for startup --- templates/postgres.template.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/postgres.template.yml b/templates/postgres.template.yml index 2dc469610..706d2a64d 100644 --- a/templates/postgres.template.yml +++ b/templates/postgres.template.yml @@ -289,7 +289,7 @@ run: tag: db hook: postgres cmd: - # wait for postgres to start up... - - sleep 5 + # give db a few secs to start up + - "sleep 5" - /usr/local/bin/create_db - "echo postgres installed!" From d46d5b378bd8a11c64baed32e1afd9eb896497a0 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Fri, 25 Jul 2025 17:48:58 -0700 Subject: [PATCH 6/6] Better formatting of if statements --- templates/web.template.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/templates/web.template.yml b/templates/web.template.yml index 0bf71ba84..8333d52df 100644 --- a/templates/web.template.yml +++ b/templates/web.template.yml @@ -61,8 +61,12 @@ run: if [[ -z "$PRECOMPILE_ON_BOOT" ]]; then PRECOMPILE_ON_BOOT=1 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 + 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: