From 2c44349a0f16ae97bf45053b61ea5851352444d1 Mon Sep 17 00:00:00 2001 From: dandax123 Date: Mon, 27 Apr 2026 17:39:45 +0200 Subject: [PATCH] feat: configure gunicorn with env variables --- compose.yaml | 4 ++++ docs/02-setup/04-env-variables.md | 10 ++++++++++ example.env | 11 +++++++++++ images/custom/Containerfile | 16 ++++------------ images/layered/Containerfile | 16 ++++------------ images/production/Containerfile | 16 ++++------------ resources/core/start.sh | 20 ++++++++++++++++++++ 7 files changed, 57 insertions(+), 36 deletions(-) create mode 100755 resources/core/start.sh diff --git a/compose.yaml b/compose.yaml index 5920e6d3..d69e4d19 100644 --- a/compose.yaml +++ b/compose.yaml @@ -46,6 +46,10 @@ services: backend: <<: *backend_defaults platform: linux/amd64 + environment: + GUNICORN_THREADS: ${GUNICORN_THREADS:-4} + GUNICORN_WORKERS: ${GUNICORN_WORKERS:-2} + GUNICORN_TIMEOUT: ${GUNICORN_TIMEOUT:-120} frontend: <<: *customizable_image diff --git a/docs/02-setup/04-env-variables.md b/docs/02-setup/04-env-variables.md index 561ee6d2..069e3231 100644 --- a/docs/02-setup/04-env-variables.md +++ b/docs/02-setup/04-env-variables.md @@ -122,6 +122,16 @@ If your site is named `example.com` and you access it via that domain, no need t --- +## Backend (Gunicorn) Configuration + +| Variable | Purpose | Default | When to Set / Allowed Values | +| :----------------- | :------------------------------------------------------------- | :------ | :------------------------------------------------------------------------------- | +| `GUNICORN_WORKERS` | Number of worker processes handling web requests | `2` | Scale up for multi-core CPUs. Formula: `(2 x Cores) + 1` | +| `GUNICORN_THREADS` | Number of concurrent threads per worker process | `4` | Increase to handle more simultaneous I/O-bound requests without high memory cost | +| `GUNICORN_TIMEOUT` | Max time a worker can spend on a single request before restart | `120` | Increase if long-running reports or data imports time out | + +--- + ## Frontend Nginx Configuration (inside the frontend container) | Variable | Purpose | Default | Allowed Values | diff --git a/example.env b/example.env index a8db8d79..893c21e3 100644 --- a/example.env +++ b/example.env @@ -15,6 +15,17 @@ DB_PORT= REDIS_CACHE= REDIS_QUEUE= + +# The number of threads per Gunicorn worker process for handling concurrent requests. +GUNICORN_THREADS=4 + +# The number of worker processes for handling requests. +# A typical formula is (2 x number of CPU cores) + 1. +GUNICORN_WORKERS=2 + +# Workers exceeding this timeout (in seconds) will be killed and restarted. +GUNICORN_TIMEOUT=120 + # Only with HTTPS override LETSENCRYPT_EMAIL=mail@example.com diff --git a/images/custom/Containerfile b/images/custom/Containerfile index 9528688b..70e4317b 100644 --- a/images/custom/Containerfile +++ b/images/custom/Containerfile @@ -165,18 +165,10 @@ USER root COPY resources/core/main-entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod 755 /usr/local/bin/entrypoint.sh +COPY resources/core/start.sh /usr/local/bin/start.sh +RUN chmod 755 /usr/local/bin/start.sh + USER frappe ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] -CMD [ \ - "/home/frappe/frappe-bench/env/bin/gunicorn", \ - "--chdir=/home/frappe/frappe-bench/sites", \ - "--bind=0.0.0.0:8000", \ - "--threads=4", \ - "--workers=2", \ - "--worker-class=gthread", \ - "--worker-tmp-dir=/dev/shm", \ - "--timeout=120", \ - "--preload", \ - "frappe.app:application" \ -] +CMD ["start.sh"] diff --git a/images/layered/Containerfile b/images/layered/Containerfile index c3326ddd..ec32cbdb 100644 --- a/images/layered/Containerfile +++ b/images/layered/Containerfile @@ -49,18 +49,10 @@ USER root COPY resources/core/main-entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod 755 /usr/local/bin/entrypoint.sh +COPY resources/core/start.sh /usr/local/bin/start.sh +RUN chmod 755 /usr/local/bin/start.sh + USER frappe ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] -CMD [ \ - "/home/frappe/frappe-bench/env/bin/gunicorn", \ - "--chdir=/home/frappe/frappe-bench/sites", \ - "--bind=0.0.0.0:8000", \ - "--threads=4", \ - "--workers=2", \ - "--worker-class=gthread", \ - "--worker-tmp-dir=/dev/shm", \ - "--timeout=120", \ - "--preload", \ - "frappe.app:application" \ -] +CMD ["start.sh"] diff --git a/images/production/Containerfile b/images/production/Containerfile index 7ad4089d..b30dd957 100644 --- a/images/production/Containerfile +++ b/images/production/Containerfile @@ -156,18 +156,10 @@ USER root COPY resources/core/main-entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod 755 /usr/local/bin/entrypoint.sh +COPY resources/core/start.sh /usr/local/bin/start.sh +RUN chmod 755 /usr/local/bin/start.sh + USER frappe ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] -CMD [ \ - "/home/frappe/frappe-bench/env/bin/gunicorn", \ - "--chdir=/home/frappe/frappe-bench/sites", \ - "--bind=0.0.0.0:8000", \ - "--threads=4", \ - "--workers=2", \ - "--worker-class=gthread", \ - "--worker-tmp-dir=/dev/shm", \ - "--timeout=120", \ - "--preload", \ - "frappe.app:application" \ -] +CMD ["start.sh"] diff --git a/resources/core/start.sh b/resources/core/start.sh new file mode 100755 index 00000000..2ac1a388 --- /dev/null +++ b/resources/core/start.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -e + +#Gunicorn defaults +GUNICORN_THREADS=${GUNICORN_THREADS:-4} +GUNICORN_WORKERS=${GUNICORN_WORKERS:-2} +GUNICORN_TIMEOUT=${GUNICORN_TIMEOUT:-120} + +echo "Booting Gunicorn with $GUNICORN_WORKERS workers and $GUNICORN_THREADS threads..." + +exec /home/frappe/frappe-bench/env/bin/gunicorn \ + --chdir=/home/frappe/frappe-bench/sites \ + --bind=0.0.0.0:8000 \ + --threads="$GUNICORN_THREADS" \ + --workers="$GUNICORN_WORKERS" \ + --worker-class=gthread \ + --worker-tmp-dir=/dev/shm \ + --timeout="$GUNICORN_TIMEOUT" \ + --preload \ + frappe.app:application