implement gunicorn WSGI

This commit is contained in:
Bryan Van Deusen
2025-08-14 13:34:29 -04:00
parent 3420cf01ff
commit 0d56daa664
4 changed files with 52 additions and 44 deletions
+3
View File
@@ -4,6 +4,7 @@ from flask import Flask
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate from flask_migrate import Migrate
from flask_login import LoginManager from flask_login import LoginManager
from werkzeug.middleware.proxy_fix import ProxyFix
db = SQLAlchemy() db = SQLAlchemy()
@@ -22,6 +23,8 @@ def create_app(config_class='config.Config'):
login_manager.init_app(app) login_manager.init_app(app)
login_manager.login_view = 'auth.login' login_manager.login_view = 'auth.login'
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1)
from app.main import main from app.main import main
from app.auth import auth from app.auth import auth
+8 -16
View File
@@ -1,31 +1,23 @@
# Dockerfile # Dockerfile
FROM python:slim FROM python:slim
# Set work directory
WORKDIR /app WORKDIR /app
# Install PostgreSQL client # Only what you actually need (ffmpeg kept for video/thumbs)
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y postgresql-client ffmpeg && \ apt-get install -y --no-install-recommends ffmpeg && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
# Copy project files # Install deps first for better layer caching
COPY requirements.txt .
RUN pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt
# Copy the rest of the app
COPY . . COPY . .
# Install dependencies # Entrypoint controls migrations, background worker, and Gunicorn
RUN pip install --upgrade pip && pip install -r requirements.txt
# Copy and prepare entrypoint script
COPY entrypoint.sh /entrypoint.sh COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh RUN chmod +x /entrypoint.sh
# Set environment variables
ENV FLASK_APP=run.py
ENV FLASK_RUN_HOST=0.0.0.0
# Expose port
EXPOSE 5000 EXPOSE 5000
# Use entrypoint script
ENTRYPOINT ["/entrypoint.sh"] ENTRYPOINT ["/entrypoint.sh"]
+39 -27
View File
@@ -1,36 +1,48 @@
#!/bin/bash #!/usr/bin/env sh
set -e
# Default to sqlite if not specified # Ensure Flask CLI finds your app
DB_TYPE="${DB_TYPE:-sqlite}" export FLASK_APP=run.py
export FLASK_ENV=production
# Wait for PostgreSQL if needed # --- Migrations with simple retry (no pg_isready needed) ---
if [ "$DB_TYPE" = "postgresql" ]; then if [ "${RUN_DB_MIGRATIONS:-1}" = "1" ]; then
MAX_WAIT=180 ATTEMPTS="${MIGRATION_MAX_ATTEMPTS:-30}" # ~90s default with 3s sleep
WAIT_INTERVAL=2 SLEEP_SECS="${MIGRATION_RETRY_SLEEP:-3}"
WAITED=0 i=1
echo "Database type is PostgreSQL. Waiting for database to be ready..." echo "Applying migrations (up to $ATTEMPTS attempts)..."
until pg_isready -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" > /dev/null 2>&1; do until flask db upgrade; do
if [ $WAITED -ge $MAX_WAIT ]; then if [ "$i" -ge "$ATTEMPTS" ]; then
echo "Timeout: Could not connect to the database at $DB_HOST:$DB_PORT within $MAX_WAIT seconds." echo "ERROR: Migrations failed after $ATTEMPTS attempts."
exit 1 exit 1
fi fi
echo "Waiting for database at $DB_HOST:$DB_PORT... ($WAITED/$MAX_WAIT seconds)" echo "DB not ready yet; retrying in ${SLEEP_SECS}s ($i/$ATTEMPTS)…"
sleep $WAIT_INTERVAL sleep "$SLEEP_SECS"
WAITED=$((WAITED + WAIT_INTERVAL)) i=$((i+1))
done done
echo "Database is ready."
else
echo "Database type is SQLite. Skipping PostgreSQL readiness check."
fi fi
# Apply migrations # --- Start the image import worker exactly once per container ---
echo "Applying database migrations..." if [ "${RUN_IMAGE_IMPORTER:-1}" = "1" ]; then
flask db upgrade echo "Starting image import worker (background)…"
python image_import_worker.py &
fi
# Start periodic image import in background # --- Start Gunicorn ---
echo "import worker waiting for flag" GUNICORN_BIND="${GUNICORN_BIND:-0.0.0.0:5000}"
python image_import_worker.py & GUNICORN_WORKERS="${GUNICORN_WORKERS:-2}"
GUNICORN_THREADS="${GUNICORN_THREADS:-4}"
GUNICORN_TIMEOUT="${GUNICORN_TIMEOUT:-120}"
GUNICORN_OPTS="${GUNICORN_OPTS:-}"
# Start the Flask app echo "Starting Gunicorn on ${GUNICORN_BIND}"
echo "Starting Flask app..." exec gunicorn \
exec flask run --host=0.0.0.0 --port=5000 --bind "${GUNICORN_BIND}" \
--workers "${GUNICORN_WORKERS}" \
--worker-class gthread \
--threads "${GUNICORN_THREADS}" \
--timeout "${GUNICORN_TIMEOUT}" \
--access-logfile - \
--error-logfile - \
${GUNICORN_OPTS} \
run:app
+1
View File
@@ -8,3 +8,4 @@ email-validator
pillow pillow
exifread exifread
imagehash imagehash
gunicorn