2025-01-08 07:06:50 -05:00
#!/bin/sh
unset BUNDLE_PATH
unset BUNDLE_BIN
set -e
2025-01-09 08:44:16 -05:00
echo " ⚠️ Starting Rails environment: $RAILS_ENV ⚠️ "
2025-01-08 07:06:50 -05:00
# Parse DATABASE_URL if present, otherwise use individual variables
if [ -n " $DATABASE_URL " ] ; then
# Extract components from DATABASE_URL
DATABASE_HOST = $( echo $DATABASE_URL | awk -F[ @/] '{print $4}' )
DATABASE_PORT = $( echo $DATABASE_URL | awk -F[ @/:] '{print $5}' )
DATABASE_USERNAME = $( echo $DATABASE_URL | awk -F[ :/@] '{print $4}' )
DATABASE_PASSWORD = $( echo $DATABASE_URL | awk -F[ :/@] '{print $5}' )
DATABASE_NAME = $( echo $DATABASE_URL | awk -F[ @/] '{print $5}' )
else
# Use existing environment variables
2025-01-09 07:04:22 -05:00
DATABASE_HOST = ${ DATABASE_HOST }
DATABASE_PORT = ${ DATABASE_PORT }
DATABASE_USERNAME = ${ DATABASE_USERNAME }
DATABASE_PASSWORD = ${ DATABASE_PASSWORD }
DATABASE_NAME = ${ DATABASE_NAME }
2025-01-08 07:06:50 -05:00
fi
2025-05-31 09:45:51 -04:00
# Export main database variables to ensure they're available
export DATABASE_HOST
export DATABASE_PORT
export DATABASE_USERNAME
export DATABASE_PASSWORD
export DATABASE_NAME
2025-01-08 07:06:50 -05:00
# Remove pre-existing puma/passenger server.pid
rm -f $APP_PATH /tmp/pids/server.pid
2025-12-06 14:34:49 -05:00
# Sync static assets from image to volume
2025-12-16 12:30:07 -05:00
# This ensures new and updated files are copied to the persistent volume
2025-12-06 14:34:49 -05:00
if [ -d "/tmp/public_assets" ] ; then
2025-12-16 12:30:07 -05:00
echo "📦 Syncing static assets to public volume..."
cp -ru /tmp/public_assets/* $APP_PATH /public/ 2>/dev/null || true
2025-12-06 14:34:49 -05:00
echo "✅ Static assets synced!"
fi
2025-05-31 13:54:12 -04:00
# Function to check and create a PostgreSQL database
2025-05-31 08:13:51 -04:00
create_database( ) {
local db_name = $1
local db_password = $2
2025-06-08 07:09:34 -04:00
local db_host = $3
local db_port = $4
local db_username = $5
2025-05-31 08:13:51 -04:00
echo " Attempting to create database $db_name if it doesn't exist... "
2025-06-08 07:09:34 -04:00
PGPASSWORD = $db_password createdb -h " $db_host " -p " $db_port " -U " $db_username " " $db_name " 2>/dev/null || echo " Note: Database $db_name may already exist or couldn't be created now "
2025-05-31 08:13:51 -04:00
# Wait for the database to become available
echo " ⏳ Waiting for database $db_name to be ready... "
2025-06-08 07:09:34 -04:00
until PGPASSWORD = $db_password psql -h " $db_host " -p " $db_port " -U " $db_username " -d " $db_name " -c '\q' 2>/dev/null; do
2025-05-31 08:13:51 -04:00
>& 2 echo " Postgres database $db_name is unavailable - retrying... "
sleep 2
done
echo " ✅ PostgreSQL database $db_name is ready! "
}
2025-05-31 13:54:12 -04:00
# Step 1: Database Setup
echo "Setting up all required databases..."
# Create primary PostgreSQL database
2025-06-08 07:09:34 -04:00
create_database " $DATABASE_NAME " " $DATABASE_PASSWORD " " $DATABASE_HOST " " $DATABASE_PORT " " $DATABASE_USERNAME "
2025-05-31 08:13:51 -04:00
2025-05-31 11:13:45 -04:00
# Step 2: Run migrations for all databases
echo "Running migrations for all databases..."
2025-05-31 09:45:51 -04:00
2025-06-06 13:36:36 -04:00
# Run primary database migrations first (needed before other migrations)
2025-05-31 13:54:12 -04:00
echo "Running primary database migrations..."
bundle exec rails db:migrate
2025-05-31 11:13:45 -04:00
2025-01-08 07:06:50 -05:00
# Run data migrations
echo "Running DATA migrations..."
bundle exec rake data:migrate
2025-05-31 13:54:12 -04:00
echo "Running seeds..."
bundle exec rails db:seed
2025-01-08 07:06:50 -05:00
# run passed commands
fix(docker): app and sidekiq containers ignore signals
Typically, when attempting to stop a container via `docker stop` or
`podman stop`, the container engine will send a stop signal (SIGTERM by
default) to the container's main process. There are two common ways this
can go wrong:
1. The main process is run as PID 1 and doesn't register a signal
handler for the stop signal and is consequently ignored
2. The main process is a shell script running a foreground process with
no `trap`s and is consequently ignored by the *shell*
In either case, because the graceful stop signal is ignored, the
container engine will then send a `SIGKILL` to the container process
after a default timeout of 10 seconds. This is why some containers can
be observed to "hang" when being stopped when they have no other reason
to do so. Unlike `SIGTERM` or `SIGINT`, `SIGKILL` is an immediate,
ungraceful stop that doesn't give the process time to clean up.
There is a fair bit of nuance in how `sh` and `bash` handle signals in
different circumstances. The behavior relevant to the second case above
and Dawarich's entrypoints in particular is that the shell ignores
signals like `SIGTERM` and `SIGINT` when waiting on a foreground job; in
this case, that would be: `bundle exec ${@}`. The reason that `SIGINT`
is not ignored after pressing `Ctrl+C` while running the docker compose
stack is because in that case the shell is **interactive** and the shell
*does* respond to `SIGINT` then (c.f. the aforementioned nuance).
Thankfully, the fix is simple: `exec` the main process, which causes the
server process to *replace* the shell process and directly receive any
signals sent. Additionally, the stop signal for the app process should
be set to `SIGINT`, as that is the expected signal for graceful
shutdown. Sidekiq is fine with either `SIGTERM` or `SIGINT`, which is
convenient.
2025-12-06 18:00:35 -05:00
exec bundle exec ${ @ }