mirror of
https://github.com/rommapp/romm.git
synced 2026-02-07 12:07:58 +08:00
The `WEB_CONCURRENCY` environment variable is a more common way to configure the number of workers for Gunicorn [1] or other web servers. This change maintains `GUNICORN_WORKERS` compatibility, while notifying users that it is deprecated and should be replaced with `WEB_CONCURRENCY`. It would also allow us to replace Gunicorn with another web server in the future without changing the variable name. [1] https://docs.gunicorn.org/en/stable/settings.html#workers
205 lines
5.6 KiB
Bash
Executable File
205 lines
5.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -o errexit # treat errors as fatal
|
|
set -o nounset # treat unset variables as an error
|
|
set -o pipefail # treat errors in pipes as fatal
|
|
shopt -s inherit_errexit # inherit errexit
|
|
|
|
# make it possible to disable the inotify watcher process
|
|
ENABLE_RESCAN_ON_FILESYSTEM_CHANGE="${ENABLE_RESCAN_ON_FILESYSTEM_CHANGE:="true"}"
|
|
|
|
# Set INIT_DEBUG to false if not set by docker env
|
|
# (this env var is currently undocumented and usually just needed for development purposes)
|
|
INIT_DEBUG="${INIT_DEBUG:="false"}"
|
|
|
|
# print debug log output if enabled
|
|
debug_log() {
|
|
if [[ ${INIT_DEBUG} == "true" ]]; then
|
|
echo "DEBUG: [init][$(date +"%Y-%m-%d %T")]" "${@}" || true
|
|
fi
|
|
}
|
|
|
|
info_log() {
|
|
echo "INFO: [init][$(date +"%Y-%m-%d %T")]" "${@}" || true
|
|
}
|
|
|
|
warn_log() {
|
|
echo "WARNING: [init][$(date +"%Y-%m-%d %T")]" "${@}" || true
|
|
}
|
|
|
|
error_log() {
|
|
echo "ERROR: [init][$(date +"%Y-%m-%d %T")]" "${@}" || true
|
|
exit 1
|
|
}
|
|
|
|
wait_for_gunicorn_socket() {
|
|
info_log "waiting for gunicorn socket file..."
|
|
while [[ ! -S /tmp/gunicorn.sock ]]; do
|
|
sleep 1
|
|
done
|
|
info_log "gunicorn socket file found"
|
|
}
|
|
|
|
# function that runs or main process and creates a corresponding PID file,
|
|
start_bin_gunicorn() {
|
|
# cleanup potentially leftover socket
|
|
rm /tmp/gunicorn.sock -f
|
|
|
|
# commands to start our main application and store its PID to check for crashes
|
|
info_log "starting gunicorn"
|
|
|
|
# TODO: Remove support for GUNICORN_WORKERS in future version.
|
|
if [[ -n ${GUNICORN_WORKERS-} ]]; then
|
|
warn_log "GUNICORN_WORKERS variable is deprecated, use WEB_CONCURRENCY instead"
|
|
: "${WEB_CONCURRENCY:=${GUNICORN_WORKERS}}"
|
|
fi
|
|
|
|
gunicorn \
|
|
--access-logfile - \
|
|
--error-logfile - \
|
|
--worker-class uvicorn.workers.UvicornWorker \
|
|
--bind=0.0.0.0:5000 \
|
|
--bind=unix:/tmp/gunicorn.sock \
|
|
--pid=/tmp/gunicorn.pid \
|
|
--forwarded-allow-ips="*" \
|
|
--workers "${WEB_CONCURRENCY:-2}" \
|
|
main:app &
|
|
}
|
|
|
|
# Commands to start nginx (handling PID creation internally)
|
|
start_bin_nginx() {
|
|
wait_for_gunicorn_socket
|
|
|
|
info_log "starting nginx"
|
|
if [[ ${EUID} -ne 0 ]]; then
|
|
nginx
|
|
else
|
|
# if container runs as root, drop permissions
|
|
nginx -g 'user romm;'
|
|
fi
|
|
}
|
|
|
|
start_bin_valkey-server() {
|
|
info_log "starting valkey-server"
|
|
# Check if /usr/local/etc/valkey/valkey.conf exists and use it if so
|
|
if [[ -f /usr/local/etc/valkey/valkey.conf ]]; then
|
|
valkey-server /usr/local/etc/valkey/valkey.conf &
|
|
else
|
|
valkey-server --dir /redis-data &
|
|
fi
|
|
VALKEY_PID=$!
|
|
echo "${VALKEY_PID}" >/tmp/valkey-server.pid
|
|
}
|
|
|
|
# function that runs our independent python scripts and creates corresponding PID files,
|
|
start_python() {
|
|
SCRIPT="${1}"
|
|
info_log "starting ${SCRIPT}.py"
|
|
python3 "${SCRIPT}.py" &
|
|
WATCHER_PID=$!
|
|
echo "${WATCHER_PID}" >"/tmp/${SCRIPT}.pid"
|
|
}
|
|
|
|
watchdog_process_pid() {
|
|
TYPE=$1
|
|
PROCESS=$2
|
|
if [[ -f "/tmp/${PROCESS}.pid" ]]; then
|
|
# check if the pid we last wrote to our state file is actually active
|
|
PID=$(cat "/tmp/${PROCESS}.pid") || true
|
|
if [[ -d "/proc/${PID}" ]]; then
|
|
debug_log "${PROCESS} still running, no need to start"
|
|
else
|
|
if [[ ${TYPE} == "bin" ]]; then
|
|
start_bin_"${PROCESS}"
|
|
elif [[ ${TYPE} == "python" ]]; then
|
|
start_python "${PROCESS}"
|
|
fi
|
|
fi
|
|
else
|
|
if [[ ${TYPE} == "bin" ]]; then
|
|
start_bin_"${PROCESS}"
|
|
elif [[ ${TYPE} == "python" ]]; then
|
|
start_python "${PROCESS}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
stop_process_pid() {
|
|
PROCESS=$1
|
|
if [[ -f "/tmp/${PROCESS}.pid" ]]; then
|
|
PID=$(cat "/tmp/${PROCESS}.pid") || true
|
|
if [[ -d "/proc/${PID}" ]]; then
|
|
info_log "stopping ${PROCESS}"
|
|
kill "${PID}" || true
|
|
# wait for process exit
|
|
while [[ -e "/proc/${PID}" ]]; do sleep 0.1; done
|
|
fi
|
|
fi
|
|
}
|
|
|
|
shutdown() {
|
|
# shutdown in reverse order
|
|
stop_process_pid scheduler
|
|
stop_process_pid worker
|
|
stop_process_pid watcher
|
|
stop_process_pid nginx
|
|
stop_process_pid gunicorn
|
|
stop_process_pid valkey-server
|
|
}
|
|
|
|
# switch to backend directory
|
|
cd /backend || { error_log "/backend directory doesn't seem to exist"; }
|
|
|
|
info_log "Starting up, please wait..."
|
|
|
|
# setup trap handler
|
|
exited=0
|
|
trap 'exited=1 && shutdown' SIGINT SIGTERM EXIT
|
|
|
|
# clear any leftover PID files
|
|
rm /tmp/*.pid -f
|
|
|
|
# function definition done, lets start our main loop
|
|
while ! ((exited)); do
|
|
# Start Valkey server if we dont have a corresponding PID file
|
|
# and REDIS_HOST is not set (which would mean we're using an external Redis/Valkey)
|
|
if [[ -z ${REDIS_HOST:=""} ]]; then
|
|
watchdog_process_pid bin valkey-server
|
|
fi
|
|
|
|
# Run needed database migrations on startup,
|
|
# but only if it was not successful since the last full docker container start
|
|
if [[ ${ALEMBIC_SUCCESS:="false"} == "false" ]]; then
|
|
if alembic upgrade head; then
|
|
debug_log "database schema migrations succeeded"
|
|
ALEMBIC_SUCCESS="true"
|
|
else
|
|
error_log "Something went horribly wrong with our database"
|
|
fi
|
|
else
|
|
debug_log "database schema already upgraded during current container lifecycle"
|
|
fi
|
|
|
|
# Start gunicorn if we dont have a corresponding PID file
|
|
watchdog_process_pid bin gunicorn
|
|
|
|
# Start nginx if we dont have a corresponding PID file
|
|
watchdog_process_pid bin nginx
|
|
|
|
# only start the watcher.py if we actually want to use the rescan on fs change feature
|
|
if [[ ${ENABLE_RESCAN_ON_FILESYSTEM_CHANGE} == "true" ]]; then
|
|
# Start watcher if we dont have a corresponding PID file
|
|
watchdog_process_pid python watcher
|
|
fi
|
|
|
|
# Start background worker processes
|
|
debug_log "Starting worker and scheduler"
|
|
# Start worker if we dont have a corresponding PID file
|
|
watchdog_process_pid python worker
|
|
# Start scheduler if we dont have a corresponding PID file
|
|
watchdog_process_pid python scheduler
|
|
|
|
# check for died processes every 5 seconds
|
|
sleep 5
|
|
done
|