142 lines
4.6 KiB
Bash
Executable file
142 lines
4.6 KiB
Bash
Executable file
#!/bin/bash
|
|
source /opt/app-root/etc/generate_container_user
|
|
|
|
set -e
|
|
|
|
function is_gunicorn_installed() {
|
|
hash gunicorn &>/dev/null
|
|
}
|
|
|
|
function is_django_installed() {
|
|
python -c "import django" &>/dev/null
|
|
}
|
|
|
|
function should_migrate() {
|
|
is_django_installed && [[ -z "$DISABLE_MIGRATE" ]]
|
|
}
|
|
|
|
# Guess the number of workers according to the number of cores
|
|
function get_default_web_concurrency() {
|
|
limit_vars=$(cgroup-limits)
|
|
local $limit_vars
|
|
if [ -z "${NUMBER_OF_CORES:-}" ]; then
|
|
echo 1
|
|
return
|
|
fi
|
|
|
|
local max=$((NUMBER_OF_CORES*2))
|
|
# Require at least 43 MiB and additional 40 MiB for every worker
|
|
local default=$(((${MEMORY_LIMIT_IN_BYTES:-MAX_MEMORY_LIMIT_IN_BYTES}/1024/1024 - 43) / 40))
|
|
default=$((default > max ? max : default))
|
|
default=$((default < 1 ? 1 : default))
|
|
# According to http://docs.gunicorn.org/en/stable/design.html#how-many-workers,
|
|
# 12 workers should be enough to handle hundreds or thousands requests per second
|
|
default=$((default > 12 ? 12 : default))
|
|
echo $default
|
|
}
|
|
|
|
function maybe_run_in_init_wrapper() {
|
|
if [[ -z "$ENABLE_INIT_WRAPPER" ]]; then
|
|
exec "$@"
|
|
else
|
|
exec $STI_SCRIPTS_PATH/init-wrapper "$@"
|
|
fi
|
|
}
|
|
|
|
APP_HOME=$(readlink -f "${APP_HOME:-.}")
|
|
# Change the working directory to APP_HOME
|
|
PYTHONPATH="$(pwd)${PYTHONPATH:+:$PYTHONPATH}"
|
|
cd "$APP_HOME"
|
|
|
|
if [ -z "$APP_SCRIPT" ] && [ -z "$APP_FILE" ] && [ -z "$APP_MODULE" ]; then
|
|
# Set default values for APP_SCRIPT and APP_FILE only when all three APP_
|
|
# variables are not defined by user. This prevents a situation when
|
|
# APP_MODULE is defined to app:application but the app.py file is found as the
|
|
# APP_FILE and then executed by Python instead of gunicorn.
|
|
APP_SCRIPT="app.sh"
|
|
APP_SCRIPT_DEFAULT=1
|
|
APP_FILE="app.py"
|
|
APP_FILE_DEFAULT=1
|
|
fi
|
|
|
|
if [ ! -z "$APP_SCRIPT" ]; then
|
|
if [[ -f "$APP_SCRIPT" ]]; then
|
|
echo "---> Running application from script ($APP_SCRIPT) ..."
|
|
if [[ "$APP_SCRIPT" != /* ]]; then
|
|
APP_SCRIPT="./$APP_SCRIPT"
|
|
fi
|
|
maybe_run_in_init_wrapper "$APP_SCRIPT"
|
|
elif [[ -z "$APP_SCRIPT_DEFAULT" ]]; then
|
|
echo "ERROR: file '$APP_SCRIPT' not found." && exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ ! -z "$APP_FILE" ]; then
|
|
if [[ -f "$APP_FILE" ]]; then
|
|
echo "---> Running application from Python script ($APP_FILE) ..."
|
|
maybe_run_in_init_wrapper python "$APP_FILE"
|
|
elif [[ -z "$APP_FILE_DEFAULT" ]]; then
|
|
echo "ERROR: file '$APP_FILE' not found." && exit 1
|
|
fi
|
|
fi
|
|
|
|
# Look for 'manage.py' in the current directory
|
|
manage_file=./manage.py
|
|
|
|
if should_migrate; then
|
|
if [[ -f "$manage_file" ]]; then
|
|
echo "---> Migrating database ..."
|
|
python "$manage_file" migrate --noinput
|
|
else
|
|
echo "WARNING: seems that you're using Django, but we could not find a 'manage.py' file."
|
|
echo "Skipped 'python manage.py migrate'."
|
|
fi
|
|
fi
|
|
|
|
# If not set, use 8080 as the default port
|
|
if [ -z "$PORT" ]; then
|
|
PORT=8080
|
|
fi
|
|
|
|
if is_gunicorn_installed; then
|
|
setup_py=$(find "$HOME" -maxdepth 2 -type f -name 'setup.py' -print -quit)
|
|
# Look for wsgi module in the current directory
|
|
if [[ -z "$APP_MODULE" && -f "./wsgi.py" ]]; then
|
|
APP_MODULE=wsgi
|
|
elif [[ -z "$APP_MODULE" && -f "$setup_py" ]]; then
|
|
APP_MODULE="$(python "$setup_py" --name)"
|
|
fi
|
|
|
|
if [[ "$APP_MODULE" ]]; then
|
|
export WEB_CONCURRENCY=${WEB_CONCURRENCY:-$(get_default_web_concurrency)}
|
|
|
|
# Default settings for gunicorn if none of the custom are set
|
|
if [ -z "$APP_CONFIG" ] && [ -z "$GUNICORN_CMD_ARGS" ]; then
|
|
GUNICORN_CMD_ARGS="--bind=0.0.0.0:$PORT --access-logfile=-"
|
|
gunicorn_settings_source="default"
|
|
else
|
|
gunicorn_settings_source="custom"
|
|
fi
|
|
|
|
# Gunicorn can read GUNICORN_CMD_ARGS as an env variable but because this is not
|
|
# supported in Gunicorn < 20 we still need for Python 2, we are using arguments directly.
|
|
echo "---> Serving application with gunicorn ($APP_MODULE) with $gunicorn_settings_source settings ..."
|
|
exec gunicorn "$APP_MODULE" $GUNICORN_CMD_ARGS --config "$APP_CONFIG"
|
|
fi
|
|
fi
|
|
|
|
if is_django_installed; then
|
|
if [[ -f "$manage_file" ]]; then
|
|
echo "---> Serving application with 'manage.py runserver 0.0.0.0:$PORT' ..."
|
|
echo "WARNING: this is NOT a recommended way to run you application in production!"
|
|
echo "Consider using gunicorn or some other production web server."
|
|
maybe_run_in_init_wrapper python "$manage_file" runserver 0.0.0.0:$PORT
|
|
else
|
|
echo "WARNING: seems that you're using Django, but we could not find a 'manage.py' file."
|
|
echo "Skipped 'python manage.py runserver'."
|
|
fi
|
|
fi
|
|
|
|
>&2 echo "ERROR: don't know how to run your application."
|
|
>&2 echo "Please set either APP_MODULE, APP_FILE or APP_SCRIPT environment variables, or create a file 'app.py' to launch your application."
|
|
exit 1
|