Introduction
Using Django Rest Framework, Celery, and Redis I created a personalized quiz to help people find roles in tech they would like. The app asks you questions and creates a custom image with your results that needs time to process in the background, so I leverage Celery and Redis to get this work done!
Now the app took me a day to build, but a week to deploy to production. Why? The age old story of hard-to-find, or nonexistent documentation. To break the broken cycle in tech Iβve created this tutorial to cover the following steps:
- How to deploy and set up Redis on Railway
- How to connect your Django server to your Redis server on Railway
- How to run your Celery workers during the build
This blog will not cover:
- The basics of Python
- Getting started with Django Rest Framework
- Getting started with Celery
- Getting started with Redis
Prerequisites
- Skills needed: Basic knowledge of Django, Redis, Celery
- Tools required: A Django Project thatβs set up to use Redis & Celery
Or you can just read along for fun if youβre not going to build with the tutorial!
Section 2: Project Overview
- Below is a simplified overview of the project structure so you can have a better understanding of how the project is structured
- For this blog, Iβve bolded the files that weβll focus on to make sure
tbc/
βββ manage.py
βββ β Procfile
βββ tbc/
β βββ __init__.py
β βββ asgi.py
β βββ settings.py
β βββ urls.py
β βββ β celery.py
β βββ wsgi.py
βββ quiz/
βββ migrations/
β βββ __init__.py
βββ __init__.py
βββ admin.py
βββ apps.py
βββ models.py
βββ serializers.py
βββ β tasks.py
βββ tests.py
βββ urls.py
βββ views.py
celery.py
import os
from celery import Celery
# Set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tbc.settings')
app = Celery('tasks',
backend=os.getenv('REDIS_URL'),
broker=os.getenv('REDIS_URL')
)
# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')
# Load task modules from all registered Django apps.
app.autodiscover_tasks()
@app.task(bind=True)
def debug_task(self):
print(f'Request: {self.request!r}')
Setting Up Railway
Create a Redis Server in Railways
Now that the files are all ready for different environments, letβs head over to the project in Railway to add a new Redis instance.
To get started, head over to your Railway dashboard and select the project you would like to add your Redis setup to. Once in the project, click '+ New' to get the service dropdown.
From the dropdown, you want to select Redis by either typing in Redis to have it pop up or selecting the database to find the Redis option.
Adding a Railways Reference Variable
In our code, we use the REDIS_URL
environment variable in our [celery.py](http://celeary.py)
file so our project can use different Redis URLs for each environment weβre working in.
For the production environment, we want our REDIS_URL
to connect to the Redis server we created in the previous step. To do this we leverage the Railway Reference variable for Redis_URL.
βΉοΈ The way I think of Railway Reference variables is a quick way to add variables for Railway-based services without having to type or copy and paste the value because the Railway defines the value for you! Want to learn more about this topic? Check out their documentation on variables here.
Running and Monitoring Celery Tasks In Railway
-
To run the Celery worker, youβll need to update your
Procfile
to look like this:
web: celery -A tbc worker --loglevel=info & python manage.py migrate && gunicorn tbc.wsgi --bind 0.0.0.0:$PORT
What is this doing?
This allows Railway to run the celery worker when the system deploys the site. Without this task running your Django app wonβt be able to connect with the celery worker.βΉοΈ You may be thinking βhey, I have to start the Redis server when Iβm running this on my local. Donβt I have to do the same for production?β And the answer is no, because Railway does it for you.
Why are we updating the Procfile
file?
When working in our local files we start our Django and Redis server before we run our celery worker and make sure we run all of our migrations.
What is a Procfile
file?
The Procfile
is how we tell the server how to run these commands and more after Railway kicks off the server.
What does the command we add mean?
By adding celery -A tbc worker --loglevel=info &
before the other commands youβre telling the Railway to run the Celery so your task can run. One thing to call out here is the order of tasks is important. Add the celery details first to avoid possible build errors you could run into if celery isnβt running during the app building.
βΉοΈ If youβre familiar with Procfile files, you might be used to seeing the file set up like it is below with the celery details under the worker. The reason weβre placing the worker details on the web line is because Railway only reads commands under the web.
```python
web: python manage.py migrate && gunicorn tbc.wsgi
worker: celery -A tbc worker --loglevel=info
```
Ready for Testing
At this stage everything is connected and ready to run to be tested in production! If you've added any logging to any of your task, you'll see this information show up in your Django server in railway.
If you hit all of your workflows and everything is working as expected, congratulations because you did it!
Conclusion
In this blog weβve set up our prod Railway environment to work with Django, Redis, and Celery!
- Weβve been able to cover
- How to set up our project to support the production environment
- Cover the steps needed to create a Redis server in Railway
- How to connect your Django server in production to your Redis server
Further Resources
- Links to documentation and more advanced guides
If you made it this far, I want to just say thanks for following along! Would love to hear your feedback and thoughts on this blog post.
Top comments (1)
It did work. I have been searching for this a week and I 'm so proud that it worked.
Please let me correct typo on the command. POR is missing T. Just add T and it will do the job
web: celery -A tbc worker --loglevel=info & python manage.py migrate && gunicorn tbc.wsgi --bind 0.0.0.0:$POR