implement gunicorn WSGI
This commit is contained in:
@@ -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
@@ -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
@@ -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)…"
|
||||||
|
|
||||||
# Start periodic image import in background
|
|
||||||
echo "import worker waiting for flag"
|
|
||||||
python image_import_worker.py &
|
python image_import_worker.py &
|
||||||
|
fi
|
||||||
|
|
||||||
# Start the Flask app
|
# --- Start Gunicorn ---
|
||||||
echo "Starting Flask app..."
|
GUNICORN_BIND="${GUNICORN_BIND:-0.0.0.0:5000}"
|
||||||
exec flask run --host=0.0.0.0 --port=5000
|
GUNICORN_WORKERS="${GUNICORN_WORKERS:-2}"
|
||||||
|
GUNICORN_THREADS="${GUNICORN_THREADS:-4}"
|
||||||
|
GUNICORN_TIMEOUT="${GUNICORN_TIMEOUT:-120}"
|
||||||
|
GUNICORN_OPTS="${GUNICORN_OPTS:-}"
|
||||||
|
|
||||||
|
echo "Starting Gunicorn on ${GUNICORN_BIND} …"
|
||||||
|
exec gunicorn \
|
||||||
|
--bind "${GUNICORN_BIND}" \
|
||||||
|
--workers "${GUNICORN_WORKERS}" \
|
||||||
|
--worker-class gthread \
|
||||||
|
--threads "${GUNICORN_THREADS}" \
|
||||||
|
--timeout "${GUNICORN_TIMEOUT}" \
|
||||||
|
--access-logfile - \
|
||||||
|
--error-logfile - \
|
||||||
|
${GUNICORN_OPTS} \
|
||||||
|
run:app
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ email-validator
|
|||||||
pillow
|
pillow
|
||||||
exifread
|
exifread
|
||||||
imagehash
|
imagehash
|
||||||
|
gunicorn
|
||||||
Reference in New Issue
Block a user