Как передать broker_url из Django settings.py в сервис Celery

У меня Celery работает как служба на Ubuntu 20.04 с RabbitMQ в качестве брокера.

Celery неоднократно перезапускается, потому что не может получить доступ к RabbitMQ url (RABBITMQ_BROKER), переменной, хранящейся в settings.py вне корневого каталога Django.

То же самое происходит, если я пытаюсь запустить celery через командную строку.

Я подтвердил, что переменная доступна из Django из оператора печати views.py.

Если я помещаю переменную RABBITMQ_BROKER в settings.py в корне Django, сельдерей работает.

Мой вопрос в том, как мне заставить celery распознать переменную RABBITMQ_BROKER, когда она помещена в /etc/opt/mydjangoproject/settings.py?

Мой файл celery.py:

import os
from celery import Celery

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backoffice.settings')

app = Celery('mydjangoproject')

default_config = 'mydjangoproject.celery_config'

app.config_from_object(default_config)
app.autodiscover_tasks()

Мой файл celery_config.py:

from django.conf import settings

broker_url = settings.RABBITMQ_BROKER
etc...

Настройки.py в /etc/opt/mydjangoproject/ (не относящийся к делу материал удален):

from mydangoproject.settings import *

RABBITMQ_BROKER = 'amqp://rabbitadmin:somepassword@somepassword@webserver:5672/mydangoproject'
etc...

Мой файл /etc/systemd/system/celery.service:

[Unit]
Description=Celery Service
After=network.target

[Service]
Type=forking
User=DJANGO_USER
Group=DJANGO_USER
EnvironmentFile=/etc/conf.d/celery
WorkingDirectory=/opt/mydjangoproject

ExecStart=/bin/sh -c '${CELERY_BIN} -A $CELERY_APP multi start $CELERYD_NODES \
   --pidfile=${CELERYD_PID_FILE} --logfile=${CELERYD_LOG_FILE} \
   --loglevel="${CELERYD_LOG_LEVEL}" $CELERYD_OPTS'
ExecStop=/bin/sh -c '${CELERY_BIN} multi stopwait $CELERYD_NODES \
    --pidfile=${CELERYD_PID_FILE} --loglevel="${CELERYD_LOG_LEVEL}"'
ExecReload=/bin/sh -c '${CELERY_BIN} -A $CELERY_APP multi restart $CELERYD_NODES \
    --pidfile=${CELERYD_PID_FILE} --logfile=${CELERYD_LOG_FILE} \
    --loglevel="${CELERYD_LOG_LEVEL}" $CELERYD_OPTS'
Restart=always

[Install]
WantedBy=multi-user.target

Мой файл /etc/conf.d/celery:

CELERYD_NODES="worker"
CELERY_BIN="/opt/mydjangoproject/venv/bin/celery"
CELERY_APP="mydjangoproject"
CELERYD_CHDIR="/opt/mydjangoproject/"
CELERYD_MULTI="multi"
CELERYD_OPTS="--time-limit=300 --without-heartbeat --without-gossip --without-mingle"
CELERYD_PID_FILE="/run/celery/%n.pid"
CELERYD_LOG_FILE="/var/log/celery/%n%I.log"
CELERYD_LOG_LEVEL="INFO"

Добавьте следующую строку в конец /etc/opt/mydjangoproject/settings.py, чтобы celery подхватил правильный url брокера (регистр может отличаться в зависимости от используемой версии celery):

BROKER_URL = broker_url = RABBITMQ_BROKER

Это поместит конфигурацию в место, где она будет прочитана вызовом функции celery config_from_object.

Далее, вам также придется добавить переменную окружения в блок systemd. Поскольку вы получаете доступ к настройкам как mydjangoproject.settings, вы должны сделать родительский каталог mydjangoproject доступным в PYTHONPATH:

Environment=PYTHONPATH=/etc/opt

Строка PYTHONPATH предоставляет python список каталогов, которые нужно попробовать при попытке импорта. Однако, поскольку у нас есть два разных каталога с одинаковым именем, которые мы используем как один пакет, нам также необходимо добавить следующие строки в /etc/opt/mydjangoproject/__init__.py и /opt/mydjangoproject/__init__.py:

import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)

Я решил эту проблему, добавив следующее в /etc/systemd/system/celery.service

Environment="PYTHONPATH=/etc/opt/mydjangoproject:/opt/mydjangoproject"
Environment="DJANGO_SETTINGS_MODULE=settings"
Вернуться на верх