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.

Вот в принципе и весь процесс шаг за шагом. Удачи!

Вернуться на верх