From 29a5e50b06a35f88e9f8e174eb2285562282bc56 Mon Sep 17 00:00:00 2001 From: Andrew Miller Date: Wed, 19 Nov 2025 20:00:33 +0000 Subject: [PATCH 1/5] Initial code changes to migrate to django-prodserver --- {{cookiecutter.project_slug}}/Procfile | 8 +-- .../production/django/celery/beat/start | 2 +- .../production/django/celery/worker/start | 2 +- .../config/settings/production.py | 67 +++++++++++++++++++ .../requirements/base.txt | 1 + 5 files changed, 74 insertions(+), 6 deletions(-) diff --git a/{{cookiecutter.project_slug}}/Procfile b/{{cookiecutter.project_slug}}/Procfile index 6424e048d3..033b90983a 100644 --- a/{{cookiecutter.project_slug}}/Procfile +++ b/{{cookiecutter.project_slug}}/Procfile @@ -1,10 +1,10 @@ release: python manage.py migrate {%- if cookiecutter.use_async == "y" %} -web: gunicorn config.asgi:application -k uvicorn_worker.UvicornWorker +web: python manage.py prodserver web {%- else %} -web: gunicorn config.wsgi:application +web: python manage.py prodserver web {%- endif %} {%- if cookiecutter.use_celery == "y" %} -worker: REMAP_SIGTERM=SIGQUIT celery -A config.celery_app worker --loglevel=info -beat: REMAP_SIGTERM=SIGQUIT celery -A config.celery_app beat --loglevel=info +worker: REMAP_SIGTERM=SIGQUIT python manage.py prodserver worker +beat: REMAP_SIGTERM=SIGQUIT python manage.py prodserver beat {%- endif %} diff --git a/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start b/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start index 42ddca9105..55b6b2984b 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start +++ b/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start @@ -5,4 +5,4 @@ set -o pipefail set -o nounset -exec celery -A config.celery_app beat -l INFO +exec ./manage.py prodserver beat diff --git a/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start b/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start index af0c8f7b52..4cb50ef108 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start +++ b/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start @@ -5,4 +5,4 @@ set -o pipefail set -o nounset -exec celery -A config.celery_app worker -l INFO +exec ./manage.py prodserver worker diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index 1981be38f9..e8c07d0dce 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -446,5 +446,72 @@ ] {%- endif %} + +# django-prodserver +# https://github.com/nanorepublica/django-prodserver +INSTALLED_APPS += ["django_prodserver"] + +PRODUCTION_PROCESSES = { +{%- if cookiecutter.use_docker == 'y' %} + {%- if cookiecutter.use_async == 'y' %} + "web": { + "BACKEND": "django_prodserver.backends.gunicorn.GunicornServer", + "ARGS": {"bind": "0.0.0.0:5000", "chdir": "/app", "worker-class": "uvicorn_worker.UvicornWorker"}, + }, + {%- else %} + "web": { + "BACKEND": "django_prodserver.backends.gunicorn.GunicornServer", + "ARGS": {"bind": "0.0.0.0:5000", "chdir": "/app"}, + }, + {%- endif %} +{%- else %} + {%- if cookiecutter.use_async == 'y' %} + "web": { + "BACKEND": "django_prodserver.backends.gunicorn.GunicornServer", + "ARGS": {"worker-class": "uvicorn_worker.UvicornWorker"}, + }, + {%- else %} + "web": { + "BACKEND": "django_prodserver.backends.gunicorn.GunicornServer", + "ARGS": {}, + }, + {%- endif %} +{%- endif %} + + # "web": { + # "BACKEND": "django_prodserver.backends.granian.GranianASGIServer", + # "ARGS": {"address": "0.0.0.0", "port": "8000", "workers": "4"}, + # }, + # "web": { + # "BACKEND": "django_prodserver.backends.granian.GranianWSGIServer", + # "ARGS": {"address": "0.0.0.0", "port": "8000", "workers": "4"}, + # }, + # "web": { + # "BACKEND": "django_prodserver.backends.waitress.WaitressServer", + # "ARGS": {}, + # }, + # "web": { + # "BACKEND": "django_prodserver.backends.uvicorn.UvicornServer", + # "ARGS": {}, + # }, + # "web": { + # "BACKEND": "django_prodserver.backends.uvicorn.UvicornWSGIServer", + # "ARGS": {}, + # }, +{%- if cookiecutter.use_celery == 'y' %} + # worker: REMAP_SIGTERM=SIGQUIT celery -A config.celery_app worker --loglevel=info + # beat: REMAP_SIGTERM=SIGQUIT celery -A config.celery_app beat --loglevel=info + "worker": { + "BACKEND": "django_prodserver.backends.celery.CeleryWorker", + "APP": "config.celery_app", + "ARGS": {"loglevel": "info"}, + }, + "beat": { + "BACKEND": "django_prodserver.backends.celery.CeleryBeat", + "APP": "config.celery_app", + "ARGS": {"loglevel": "info"}, + }, +{%- endif %} +} # Your stuff... # ------------------------------------------------------------------------------ diff --git a/{{cookiecutter.project_slug}}/requirements/base.txt b/{{cookiecutter.project_slug}}/requirements/base.txt index 9adb7e5b88..95d161e46c 100644 --- a/{{cookiecutter.project_slug}}/requirements/base.txt +++ b/{{cookiecutter.project_slug}}/requirements/base.txt @@ -34,6 +34,7 @@ django-environ==0.12.0 # https://github.com/joke2k/django-environ django-model-utils==5.0.0 # https://github.com/jazzband/django-model-utils django-allauth[mfa]==65.13.0 # https://github.com/pennersr/django-allauth django-crispy-forms==2.5 # https://github.com/django-crispy-forms/django-crispy-forms +django-prodserver==2.3.0 # https://github.com/nanorepublica/django-prodserver crispy-bootstrap5==2025.6 # https://github.com/django-crispy-forms/crispy-bootstrap5 {%- if cookiecutter.frontend_pipeline == 'Django Compressor' %} django-compressor==4.5.1 # https://github.com/django-compressor/django-compressor From 6103b4aa53b30f41a89efea1c9bcab2a10c80b99 Mon Sep 17 00:00:00 2001 From: Andrew Miller Date: Wed, 19 Nov 2025 19:54:01 +0000 Subject: [PATCH 2/5] Remove extras --- .../config/settings/production.py | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index e8c07d0dce..f24c4e41e9 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -477,27 +477,6 @@ }, {%- endif %} {%- endif %} - - # "web": { - # "BACKEND": "django_prodserver.backends.granian.GranianASGIServer", - # "ARGS": {"address": "0.0.0.0", "port": "8000", "workers": "4"}, - # }, - # "web": { - # "BACKEND": "django_prodserver.backends.granian.GranianWSGIServer", - # "ARGS": {"address": "0.0.0.0", "port": "8000", "workers": "4"}, - # }, - # "web": { - # "BACKEND": "django_prodserver.backends.waitress.WaitressServer", - # "ARGS": {}, - # }, - # "web": { - # "BACKEND": "django_prodserver.backends.uvicorn.UvicornServer", - # "ARGS": {}, - # }, - # "web": { - # "BACKEND": "django_prodserver.backends.uvicorn.UvicornWSGIServer", - # "ARGS": {}, - # }, {%- if cookiecutter.use_celery == 'y' %} # worker: REMAP_SIGTERM=SIGQUIT celery -A config.celery_app worker --loglevel=info # beat: REMAP_SIGTERM=SIGQUIT celery -A config.celery_app beat --loglevel=info From 648884b9bbc8e2fb1526adae85e5e6cee434bfa6 Mon Sep 17 00:00:00 2001 From: Andrew Miller Date: Wed, 19 Nov 2025 20:16:28 +0000 Subject: [PATCH 3/5] Update some references from `runserver` to `devserver` --- docs/2-local-development/developing-locally.rst | 2 +- {{cookiecutter.project_slug}}/gulpfile.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/2-local-development/developing-locally.rst b/docs/2-local-development/developing-locally.rst index c6f052ea75..9d8e8a190a 100644 --- a/docs/2-local-development/developing-locally.rst +++ b/docs/2-local-development/developing-locally.rst @@ -65,7 +65,7 @@ Make sure to have the following on your host: #. If you're running synchronously, see the application being served through Django development server: :: - uv run python manage.py runserver 0.0.0.0:8000 + uv run python manage.py devserver 0.0.0.0:8000 or if you're running asynchronously: :: diff --git a/{{cookiecutter.project_slug}}/gulpfile.mjs b/{{cookiecutter.project_slug}}/gulpfile.mjs index 41f02b78ec..c4dad98467 100644 --- a/{{cookiecutter.project_slug}}/gulpfile.mjs +++ b/{{cookiecutter.project_slug}}/gulpfile.mjs @@ -121,7 +121,7 @@ function asyncRunServer() { {%- else %} // Run django server function runServer(cb) { - const cmd = spawn('python', ['manage.py', 'runserver'], { stdio: 'inherit' }); + const cmd = spawn('python', ['manage.py', 'devserver'], { stdio: 'inherit' }); cmd.on('close', function (code) { console.log('runServer exited with code ' + code); cb(code); From 088a3e7e85eda2f170e5aa65a77170e30da702e1 Mon Sep 17 00:00:00 2001 From: Andrew Miller Date: Wed, 26 Nov 2025 19:59:10 +0000 Subject: [PATCH 4/5] Some cleanup and added references to prodserver docs --- docs/1-getting-started/settings.rst | 1 + {{cookiecutter.project_slug}}/Procfile | 4 ---- .../compose/production/django/celery/beat/start | 2 +- .../compose/production/django/celery/worker/start | 2 +- .../compose/production/django/start | 7 ++----- .../config/settings/production.py | 2 +- 6 files changed, 6 insertions(+), 12 deletions(-) diff --git a/docs/1-getting-started/settings.rst b/docs/1-getting-started/settings.rst index dfdccc7cc9..b5abf271fd 100644 --- a/docs/1-getting-started/settings.rst +++ b/docs/1-getting-started/settings.rst @@ -72,6 +72,7 @@ BREVO_API_KEY BREVO_API_KEY n/a BREVO_API_URL n/a n/a "https://api.brevo.com/v3/" SPARKPOST_API_KEY SPARKPOST_API_KEY n/a raises error SPARKPOST_API_URL n/a n/a "https://api.sparkpost.com/api/v1" +n/a PRODUCTION_PROCESSES n/a a configured dictionary depending on your choices - check settings/production.py ======================================= =========================== ============================================== ====================================================================== -------------------------- diff --git a/{{cookiecutter.project_slug}}/Procfile b/{{cookiecutter.project_slug}}/Procfile index 033b90983a..43657d99c6 100644 --- a/{{cookiecutter.project_slug}}/Procfile +++ b/{{cookiecutter.project_slug}}/Procfile @@ -1,9 +1,5 @@ release: python manage.py migrate -{%- if cookiecutter.use_async == "y" %} web: python manage.py prodserver web -{%- else %} -web: python manage.py prodserver web -{%- endif %} {%- if cookiecutter.use_celery == "y" %} worker: REMAP_SIGTERM=SIGQUIT python manage.py prodserver worker beat: REMAP_SIGTERM=SIGQUIT python manage.py prodserver beat diff --git a/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start b/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start index 55b6b2984b..0bd085aba2 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start +++ b/{{cookiecutter.project_slug}}/compose/production/django/celery/beat/start @@ -4,5 +4,5 @@ set -o errexit set -o pipefail set -o nounset - +# https://django-prodserver.readthedocs.io/en/latest/ exec ./manage.py prodserver beat diff --git a/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start b/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start index 4cb50ef108..711974a268 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start +++ b/{{cookiecutter.project_slug}}/compose/production/django/celery/worker/start @@ -4,5 +4,5 @@ set -o errexit set -o pipefail set -o nounset - +# https://django-prodserver.readthedocs.io/en/latest/ exec ./manage.py prodserver worker diff --git a/{{cookiecutter.project_slug}}/compose/production/django/start b/{{cookiecutter.project_slug}}/compose/production/django/start index f45e7b28d4..9db27281a4 100644 --- a/{{cookiecutter.project_slug}}/compose/production/django/start +++ b/{{cookiecutter.project_slug}}/compose/production/django/start @@ -27,8 +27,5 @@ if compress_enabled; then python /app/manage.py compress fi {%- endif %} -{%- if cookiecutter.use_async == 'y' %} -exec gunicorn config.asgi --bind 0.0.0.0:5000 --chdir=/app -k uvicorn_worker.UvicornWorker -{%- else %} -exec gunicorn config.wsgi --bind 0.0.0.0:5000 --chdir=/app -{%- endif %} +# https://django-prodserver.readthedocs.io/en/latest/ +exec python /app/manage.py prodserver web diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index f24c4e41e9..145b4cac50 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -448,7 +448,7 @@ {%- endif %} # django-prodserver -# https://github.com/nanorepublica/django-prodserver +# https://django-prodserver.readthedocs.io/en/latest/ INSTALLED_APPS += ["django_prodserver"] PRODUCTION_PROCESSES = { From ce3024143f75d751fc59f92911a97417a40ef691 Mon Sep 17 00:00:00 2001 From: Andrew Miller Date: Thu, 27 Nov 2025 08:37:32 +0000 Subject: [PATCH 5/5] comment cleanup --- {{cookiecutter.project_slug}}/config/settings/production.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/{{cookiecutter.project_slug}}/config/settings/production.py b/{{cookiecutter.project_slug}}/config/settings/production.py index 145b4cac50..2295971663 100644 --- a/{{cookiecutter.project_slug}}/config/settings/production.py +++ b/{{cookiecutter.project_slug}}/config/settings/production.py @@ -478,8 +478,6 @@ {%- endif %} {%- endif %} {%- if cookiecutter.use_celery == 'y' %} - # worker: REMAP_SIGTERM=SIGQUIT celery -A config.celery_app worker --loglevel=info - # beat: REMAP_SIGTERM=SIGQUIT celery -A config.celery_app beat --loglevel=info "worker": { "BACKEND": "django_prodserver.backends.celery.CeleryWorker", "APP": "config.celery_app",