如何将 broker_url 从 Django settings.py 传递到 Celery 服务

How to pass broker_url from Django settings.py to a Celery service

我将 Celery 运行 作为 Ubuntu 20.04 上的一项服务,并将 RabbitMQ 作为代理。

Celery 反复重启,因为它无法访问 RabbitMQ url (RABBITMQ_BROKER),一个保存在 settings.py outside 的变量Django 根目录.

如果我尝试通过命令行启动 celery,也会发生同样的情况。

我已经确认可以通过 views.py print 语句在 Django 中访问该变量。

如果我将 RABBITMQ_BROKER 变量放在 Django 根芹菜工程中的 settings.py 中。

我的问题是,当 celery 放在 /etc/opt/mydjangoproject/settings.py 中时,如何让 celery 识别变量 RABBITMQ_BROKER?

我的 celery.py 文件:

import os
from celery import Celery

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mydjangoproject.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...

/etc/opt/mydjangoproject/中的settings.py(不相关内容已删除):

from mydangoproject.settings import *

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

我的/etc/systemd/system/celery.服务文件:

[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 尝试导入时要尝试的目录列表。但是,因为我们有两个同名的不同目录,我们将它们用作单个包,we also have to add the following lines to /etc/opt/mydjangoproject/__init__.py and /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"