Django Celery with Redis Issues on Digital Ocean App Platform
Asked Answered
Q

1

7

After quite a bit of trial and error and a step by step attempt to find solutions I thought I share the problems here and answer them myself according to what I've found. There is not too much documentation on this anywhere except small bits and pieces and this will hopefully help others in the future.

Please note that this is specific to Django, Celery, Redis and the Digital Ocean App Platform.

This is mostly about the below errors and further resulting implications:

OSError: [Errno 38] Function not implemented

and

Cannot connect to redis://......

The first error happens when you try run the celery command celery -A your_app worker --beat -l info or similar on the App Platform. It appears that this is currently not supported on digital ocean. The second error occurs when you make a number of potential mistakes.

Quincyquindecagon answered 26/11, 2021 at 18:13 Comment(0)
Q
12

PART 1:

While Digital Ocean might remedy this in the future here is an approach that will offer a workaround. The problem is the not supported execution pool. Google "celery execution pools" if you want to know more and how they work. The default one is prefork. But what you need is either gevent or eventlet. I went with the former for my purposes.

Whichever you pick you will have to install it as it doesn't come with celery by default. In my case it was: pip install gevent (and don't forget adding it to your requirements as well).

Once you have that you can re-run the celery command but note that gevent and beat are not supported within a single command (will result in an error). Instead do the following:

celery -A your_app worker --pool=gevent -l info and then separately (if you want to run beat that is) in another terminal/console celery -A your_app beat -l info

In the first line you can also specify the concurrency like so: --concurrency=100. This is not required but useful. Read up on it what it does as that goes beyond the solution here.

PART 2: In my specific case I've tested the above locally (development) first to make sure they work. The next issue was getting this into production. I use Redis as the db/broker.

In my specific setup I have most of my celery configuration in the_main_app/celery/__init__.py file but sometimes people put it directly into the_main_app/celery.py. Whichever it is you do make sure that the REDIS_URL is set correctly. For development it usually looks something like this:

YOUR_VAR_NAME = os.environ.get('REDIS_URL', 'redis://localhost:6379') where YOUR_VAR_NAME is then set to the broker with everything as below:

YOUR_VAR_NAME = os.environ.get('REDIS_URL', 'redis://localhost:6379')
app = Celery('the_main_app')
app.conf.broker_url = YOUR_VAR_NAME

The remaining settings are all documented on the "celery first steps with django" help page but are not relevant for what I am showing here.

PART 3:

When you setup your Redis Database on the App Platform (which is very simple) you will see the connection details as 'public network' and 'VPC network'.

The celery documentation says to use the following URL format for production: redis://:password@hostname:port/db_number. This didn't work. If you are not using a yaml file then you can simply copy paste the entire connection string (select from the dropdown!) from the Redis DB connection details and then setup an App-Level environment variable in your Digital Ocean project named REDIS_URL and paste in that entire string (and also encrypt it!).

The string should look like something like this (redis with 2 s!) rediss://USER:[email protected]:PORT.

You are almost done. The last step is to setup the workers. It was fine for me to run the PART 1 commands as console commands on the App Platform to test them but eventually I've setup a small worker (+ Add Component) for each line pasted them into the Run Command.

That is basically the process step by step. Good luck!

Quincyquindecagon answered 26/11, 2021 at 18:13 Comment(6)
Thanks for the excellent write-up on this. Can I ask, how you created your worker for celery? DO docs says to create a new resource: docs.digitalocean.com/products/app-platform/how-to/… but this will incur an additional $12 just to run a background task. Is there a better way that won't inflate the price of the plan?Comity
No problem at all. My pleasure. Good if it helps. To your follow up question: unfortunately yes, I opted to create new "workers" on the platform for each main additional process which is in this case the celery-worker and celery-beat. You can't really run this (well) through the primary (web app) component. PS: That doesn't mean that there might be other ways that I am not aware of but I think that is probably the best option.Quincyquindecagon
The gevent configuration solved my problem! Thank you very much!Ary
I am gettings this error, on digital ocean redis with private network SecurityWarning: You're running the worker with superuser privileges: this is absolutely not recommended! Please specify a different user using the --uid option. User information: uid=0 euid=0 gid=0 egid=0Jammiejammin
@umairmehmood this is not an error as such but rather a warning. There are a number of solutions for this on the web. Here is one for example: #59651928Quincyquindecagon
@Quincyquindecagon yes it is a warning but it makes docker celery service to keep failing.Jammiejammin

© 2022 - 2024 — McMap. All rights reserved.