Django Celery с проблемами Redis на платформе Digital Ocean App Platform
После довольно большого количества проб и ошибок и пошаговых попыток найти решение я решил поделиться здесь проблемами и ответить на них в соответствии с тем, что я нашел. Документации по этому вопросу не так много, кроме небольших кусочков, и это, надеюсь, поможет другим в будущем.
Обратите внимание, что это относится к Django, Celery, Redis и Digital Ocean App Platform.
В основном речь идет о следующих ошибках и дальнейших вытекающих из них последствиях:
OSError: [Errno 38] Функция не реализована
и
Не удается подключиться к redis://......
Первая ошибка возникает при попытке выполнить команду celery celery -A your_app worker --beat -l info
или аналогичную на платформе App Platform. Похоже, что в настоящее время это не поддерживается на digital ocean. Вторая ошибка возникает, когда вы совершаете ряд возможных ошибок.
ЧАСТЬ 1:
Хотя Digital Ocean может исправить это в будущем, вот подход, который предлагает обходной путь. Проблема заключается в неподдерживаемом пуле выполнения. Если вы хотите узнать больше и как они работают, введите в Google "celery execution pools". По умолчанию используется prefork
. Но вам нужен либо gevent
, либо eventlet
. Для своих целей я выбрал первый вариант.
Какой бы вариант вы ни выбрали, вам придется установить его, поскольку по умолчанию он не поставляется с celery. В моем случае это было так: pip install gevent
(и не забудьте также добавить его в ваши требования).
После этого вы можете повторно запустить команду celery, но обратите внимание, что gevent
и beat
не поддерживаются в рамках одной команды (приведет к ошибке). Вместо этого выполните следующие действия:
celery -A your_app worker --pool=gevent -l info
и затем отдельно (если вы хотите запустить beat то есть) в другом терминале/консоли
celery -A your_app beat -l info
В первой строке вы также можете указать concurrency
, например: --concurrency=100
. Это не обязательно, но полезно. Почитайте о том, что это делает, так как это выходит за рамки данного решения.
ЧАСТЬ 2: В моем конкретном случае я сначала протестировал все вышеперечисленное локально (разработка), чтобы убедиться, что они работают. Следующей проблемой стало внедрение этого в производство. Я использую Redis в качестве базы данных/брокера.
В моей конкретной установке большая часть конфигурации celery находится в файле the_main_app/celery/__init__.py
, но иногда люди помещают ее непосредственно в the_main_app/celery.py
. Что бы вы ни делали, убедитесь, что REDIS_URL установлен правильно. Для разработки он обычно выглядит примерно так:
YOUR_VAR_NAME = os.environ.get('REDIS_URL', 'redis://localhost:6379')
, где YOUR_VAR_NAME
затем устанавливается брокер со всем, как показано ниже:
YOUR_VAR_NAME = os.environ.get('REDIS_URL', 'redis://localhost:6379')
app = Celery('the_main_app')
app.conf.broker_url = YOUR_VAR_NAME
Остальные настройки описаны на странице помощи "celery first steps with django", но они не относятся к тому, что я здесь показываю.
ЧАСТЬ 3:
При настройке базы данных Redis на App Platform (что очень просто) вы увидите детали подключения как 'public network' и 'VPC network'.
В документации celery говорится, что для производства следует использовать следующий формат URL: redis://:password@hostname:port/db_number
. Это не сработало. Если вы не используете yaml-файл, то вы можете просто скопировать и вставить всю строку подключения (выберите из выпадающего списка!) из деталей подключения к Redis DB, а затем установить переменную окружения App-Level в вашем проекте Digital Ocean с именем и вставить всю эту строку (а также зашифровать ее!).REDIS_URL
Строка должна выглядеть примерно так (redis with 2 s!)
rediss://USER:PASS@URL.db.ondigitialocean.com:PORT
.
Вы почти закончили. Последний шаг - это настройка рабочих. Мне было удобно запускать команды ЧАСТИ 1 как консольные команды на App Platform для их тестирования, но в итоге я настроил небольшой рабочий (+ Добавить компонент) для каждой строки, вставив их в команду Run Command.
Вот в принципе и весь процесс шаг за шагом. Удачи!