diff --git a/Dockerfile b/Dockerfile index f64bb57e..d513fc6a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,7 +61,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ apt-get update && apt-get install -y --no-install-recommends \ libpq5 \ curl \ - wget \ && apt-get upgrade -y # Create non-root user for security @@ -110,7 +109,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ apt-get update && apt-get install -y --no-install-recommends \ libpq5 \ curl \ - wget \ && apt-get upgrade -y # Create non-root user for security @@ -121,7 +119,8 @@ RUN groupadd -r appuser && \ ENV PYTHONUNBUFFERED=1 \ PYTHONPATH=/app/src \ PATH="/app/.venv/bin:$PATH" \ - VIRTUAL_ENV=/app/.venv + VIRTUAL_ENV=/app/.venv \ + DJANGO_Q_WORKERS=1 WORKDIR /app diff --git a/src/gunicorn_config.py b/src/gunicorn_config.py index 73b8cdef..cf444c12 100644 --- a/src/gunicorn_config.py +++ b/src/gunicorn_config.py @@ -64,13 +64,18 @@ # A positive integer. Generally set in the 1-5 seconds range. # -workers = 3 +workers = 1 +threads = 2 worker_class = "gthread" worker_connections = 1000 timeout = 30 keepalive = 2 worker_tmp_dir = "/dev/shm" +# Memory leak mitigation - restart workers after handling N requests +max_requests = 1000 +max_requests_jitter = 50 + # preload_app - Load application code before forking worker processes. # This conserves memory and speeds up server boot times by loading # the Django application once in the main process, then forking diff --git a/src/settings/components/base.py b/src/settings/components/base.py index 01a8150c..80fc3799 100644 --- a/src/settings/components/base.py +++ b/src/settings/components/base.py @@ -104,7 +104,7 @@ # Django-Q2 configuration (sync mode for testing, use redis/orm in production) Q_CLUSTER = { "name": "operationcode", - "workers": 2, + "workers": config("DJANGO_Q_WORKERS", default=1, cast=int), "timeout": 60, "retry": 120, "queue_limit": 50,