Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/1-getting-started/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
======================================= =========================== ============================================== ======================================================================

--------------------------
Expand Down
2 changes: 1 addition & 1 deletion docs/2-local-development/developing-locally.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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: ::

Expand Down
10 changes: 3 additions & 7 deletions {{cookiecutter.project_slug}}/Procfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
release: python manage.py migrate
{%- if cookiecutter.use_async == "y" %}
web: gunicorn config.asgi:application -k uvicorn_worker.UvicornWorker
{%- else %}
web: gunicorn config.wsgi:application
{%- endif %}
web: python manage.py prodserver web
{%- 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
Comment on lines +4 to +5
Copy link
Member

@browniebroke browniebroke Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to deploy that to heroku and I'm getting some errors (Sentry public link)

Logs

Worker process:

heroku/worker.1 Starting process with command `REMAP_SIGTERM=SIGQUIT python manage.py prodserver worker`
heroku/worker.1 State changed from starting to up
app/worker.1 Starting server named worker
app/worker.1 Traceback (most recent call last):
app/worker.1   File "/app/manage.py", line 30, in <module>
app/worker.1     main()
app/worker.1     ~~~~^^
app/worker.1   File "/app/manage.py", line 26, in main
app/worker.1     execute_from_command_line(sys.argv)
app/worker.1     ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
app/worker.1   File "/app/.heroku/python/lib/python3.13/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
app/worker.1     utility.execute()
app/worker.1     ~~~~~~~~~~~~~~~^^
app/worker.1   File "/app/.heroku/python/lib/python3.13/site-packages/django/core/management/__init__.py", line 436, in execute
app/worker.1     self.fetch_command(subcommand).run_from_argv(self.argv)
app/worker.1     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
app/worker.1   File "/app/.heroku/python/lib/python3.13/site-packages/django_prodserver/management/commands/prodserver.py", line 64, in run_from_argv
app/worker.1     self.start_server(*args, **cmd_options)
app/worker.1     ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
app/worker.1   File "/app/.heroku/python/lib/python3.13/site-packages/django_prodserver/management/commands/prodserver.py", line 102, in start_server
app/worker.1     backend.start_server(*backend.prep_server_args())
app/worker.1     ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/worker.1   File "/app/.heroku/python/lib/python3.13/site-packages/django_prodserver/backends/celery.py", line 18, in start_server
app/worker.1     self.app.Worker(*args).start()
app/worker.1     ~~~~~~~~~~~~~~~^^^^^^^
app/worker.1   File "/app/.heroku/python/lib/python3.13/site-packages/celery/worker/worker.py", line 94, in __init__
app/worker.1     self.app.loader.init_worker()
app/worker.1     ^^^^^^^^^^^^^^^
app/worker.1 AttributeError: 'str' object has no attribute 'loader'. Did you mean: 'lower'?
app/worker.1 Sentry is attempting to send 2 pending events
app/worker.1 Waiting up to 2 seconds
app/worker.1 Press Ctrl-C to quit
heroku/worker.1 State changed from up to crashed
heroku/worker.1 Process exited with status 1

Beat process:

app/beat.1 Starting server named beat
app/beat.1 Traceback (most recent call last):
app/beat.1   File "/app/manage.py", line 30, in <module>
app/beat.1     main()
app/beat.1     ~~~~^^
app/beat.1   File "/app/manage.py", line 26, in main
app/beat.1     execute_from_command_line(sys.argv)
app/beat.1     ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
app/beat.1   File "/app/.heroku/python/lib/python3.13/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
app/beat.1     utility.execute()
app/beat.1     ~~~~~~~~~~~~~~~^^
app/beat.1   File "/app/.heroku/python/lib/python3.13/site-packages/django/core/management/__init__.py", line 436, in execute
app/beat.1     self.fetch_command(subcommand).run_from_argv(self.argv)
app/beat.1     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
app/beat.1   File "/app/.heroku/python/lib/python3.13/site-packages/django_prodserver/management/commands/prodserver.py", line 64, in run_from_argv
app/beat.1     self.start_server(*args, **cmd_options)
app/beat.1     ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
app/beat.1   File "/app/.heroku/python/lib/python3.13/site-packages/django_prodserver/management/commands/prodserver.py", line 102, in start_server
app/beat.1     backend.start_server(*backend.prep_server_args())
app/beat.1     ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/beat.1   File "/app/.heroku/python/lib/python3.13/site-packages/django_prodserver/backends/celery.py", line 26, in start_server
app/beat.1     self.app.Beat(*args).start()
app/beat.1     ^^^^^^^^^^^^^^^^^^^^^^^^^^
app/beat.1 AttributeError: 'Beat' object has no attribute 'start'
app/beat.1 Sentry is attempting to send 2 pending events
app/beat.1 Waiting up to 2 seconds
app/beat.1 Press Ctrl-C to quit
heroku/beat.1 State changed from up to crashed
heroku/beat.1 Process exited with status 1

That might have been due to a change in Celery... ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a project that was possibly erroring like this when trying to add celery with prodserver. Hopefully I'll have time over Christmas to look at this!

{%- endif %}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ set -o errexit
set -o pipefail
set -o nounset


exec celery -A config.celery_app beat -l INFO
# https://django-prodserver.readthedocs.io/en/latest/
exec ./manage.py prodserver beat
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ set -o errexit
set -o pipefail
set -o nounset


exec celery -A config.celery_app worker -l INFO
# https://django-prodserver.readthedocs.io/en/latest/
exec ./manage.py prodserver worker
7 changes: 2 additions & 5 deletions {{cookiecutter.project_slug}}/compose/production/django/start
Original file line number Diff line number Diff line change
Expand Up @@ -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
46 changes: 46 additions & 0 deletions {{cookiecutter.project_slug}}/config/settings/production.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,5 +446,51 @@
]

{%- endif %}

# django-prodserver
# https://django-prodserver.readthedocs.io/en/latest/
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 %}
{%- 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...
# ------------------------------------------------------------------------------
2 changes: 1 addition & 1 deletion {{cookiecutter.project_slug}}/gulpfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions {{cookiecutter.project_slug}}/requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.1 # 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
Expand Down