使用 Supervisor 启动 Celery 时如何避免 SECRET_KEY 错误?

Posted

技术标签:

【中文标题】使用 Supervisor 启动 Celery 时如何避免 SECRET_KEY 错误?【英文标题】:How to avoid SECRET_KEY error when starting Celery using Supervisor? 【发布时间】:2015-06-13 15:07:03 【问题描述】:

我有一个 Django 1.62 应用程序在 Debian 7.8 上运行,nginx 1.2.1 作为我的代理服务器,Gunicorn 19.1.1 作为我的应用程序服务器。我已经安装了 Celery 3.1.7 和 RabbitMQ 2.8.4 来处理异步任务。我正在尝试使用 Supervisor 3.0a8 管理我的各种应用程序,尤其是 Celery。问题是,当我尝试通过 Supervisor 启动 Celery 时,出现此错误:

ImproperlyConfigured: The SECRET_KEY setting must not be empty.

(我在底部显示了整个堆栈跟踪。)

我的所有配置文件都保存在一个“conf”目录中,该目录位于我的“myproj”项目目录的正下方,如下所示:

conf
├── celeryconfig.py
├── celeryconfig.pyc
├── celery.py
├── __init__.py
├── middleware.py
├── settings
│   ├── base.py
│   ├── dev.py
│   ├── __init__.py
│   ├── prod.py
├── urls.py
├── wsgi.py

我的生产 Django 设置保存在 prod.py 设置文件中,该文件继承了我的 base.py 基本设置。我将密钥保存在我的虚拟环境的 postactivate 文件中,并将其读入我的生产设置中,如下所示。我已经通过 Python 解释器验证了密钥存在于我的生产设置中。

# conf/settings/prod.py
from conf.settings.base import *
...
# get_env_variable is defined in base.py
SECRET_KEY = get_env_variable("SECRET_KEY")

这是读取密钥的 get_env_variable 函数:

# conf/settings/base.py
def get_env_variable(var_name):
    try:
        return os.environ[var_name]
    except KeyError:
        error_msg = "Set the %s environment variable" % var_name
        raise ImproperlyConfigured(error_msg)

这是我的主管配置文件。它基于Celery documentation 中显示的示例文件:

# /etc/supervisor/conf.d/myproj.conf
[program:myproj]
command = /www/myproj/bin/start-gunicorn
user = root
stdout_logfile = /var/log/gunicorn/supervisor.log
redirect_stderr = true

[program:celery]
directory=/www/myproj
command=/home/myproj/venv/myproj/bin/celery worker --app=conf -l debug
user=nobody
numprocs=1
stdout_logfile=/var/log/celery/celery.log
stderr_logfile=/var/log/celery/celery.log
autostart=true
autorestart=true
startsecs=10
stopwaitsecs=600
killasgroup=true
priority=998

这是我使用 Supervisor 加载新 Celery 配置的方式:

sudo service supervisor stop
sudo service supervisor start

这是我的 Celery 应用程序文件:

# conf/celery.py
from __future__ import absolute_import
import os
from celery import Celery
from django.conf import settings
from conf import celeryconfig

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'conf.settings')
app = Celery('conf')
app.config_from_object(celeryconfig)
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

这是我的 Celery 配置文件:

# conf/celeryconfig.py
BROKER_URL = 'amqp://guest@localhost:5672//'
CELERY_RESULT_BACKEND = 'amqp'
CELERY_ACCEPT_CONTENT = ['json', ]
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TASK_RESULT_EXPIRES = 3600
CELERY_SEND_TASK_ERROR_EMAILS = True

根据 Celery 文档,我修改了 __init__.py:

# conf/__init__.py
from __future__ import absolute_import
from .celery import app as celery_app

我可以使用以下命令手动启动 Celery,它启动得很好:

workon myproj  # Activate project's virtual environment
celery worker -A conf -l info

但是,当我尝试通过 Supervisor 启动它时,我得到了我所描述的错误。考虑到主管可能无法访问 Django 密钥,因为它是一个环境变量,我尝试在我的 prod.py 设置文件中对密钥进行硬编码(而不是通过 get_env_variable 函数读取它),但这并没有解决问题。

我尝试将我的所有设置合并到包含实际密钥的 prod.py 设置文件中,但这没有帮助。

我还尝试将此环境参数添加到主管配置文件中,如下所示,但这并没有解决问题:

# /etc/supervisor/conf.d/myproj.conf
...
[program:celery]
environment=SECRET_KEY="(my secret key)"
directory=/www/myproj
command=/home/myproj/venv/myproj/bin/celery worker --app=conf -l debug
user=nobody
...

我尝试将“用户”设置为我启动网站时的用户名,但这也无济于事。

# /etc/supervisor/conf.d/myproj.conf
...
[program:celery]
environment=SECRET_KEY="(my secret key)"
directory=/www/myproj
command=/home/myproj/venv/myproj/bin/celery worker --app=conf -l debug
user=myproj
...

我读到了一个名为 django-supervisor 的库,它应该可以简化 Django 和 Supervisor 之间的集成,但如果我使用该库,我会遇到同样的错误。

最后我读到here on SO,如果你的密钥包含“%”符号,Supervisor 不会喜欢它。我注意到我的密钥确实包含一个“%”符号,所以我像这个“%%”一样对其进行了转义,但这也没有解决问题。

谁能看到我做错了什么?我在这里看到了来自在不同情况下遇到相同错误的用户提出的其他问题,但我尝试实施讨论过的各种解决方案,但都没有解决问题。

非常感谢您的想法。很抱歉这个问题很长,但这个问题有很多活动部分。

这是整个堆栈跟踪:

Traceback (most recent call last):
  File "/home/myproj/venv/myproj/bin/celery", line 11, in <module>
    sys.exit(main())
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/__main__.py", line 30, in main
    main()
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/bin/celery.py", line 81, in main
    cmd.execute_from_commandline(argv)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/bin/celery.py", line 769, in execute_from_commandline
    super(CeleryCommand, self).execute_from_commandline(argv)))
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/bin/base.py", line 307, in execute_from_commandline
    return self.handle_argv(self.prog_name, argv[1:])
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/bin/celery.py", line 761, in handle_argv
    return self.execute(command, argv)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/bin/celery.py", line 693, in execute
    ).run_from_argv(self.prog_name, argv[1:], command=argv[0])
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/bin/worker.py", line 179, in run_from_argv
    return self(*args, **options)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/bin/base.py", line 270, in __call__
    ret = self.run(*args, **kwargs)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/bin/worker.py", line 212, in run
    state_db=self.node_format(state_db, hostname), **kwargs
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/worker/__init__.py", line 95, in __init__
    self.app.loader.init_worker()
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/loaders/base.py", line 128, in init_worker
    self.import_default_modules()
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/loaders/base.py", line 116, in import_default_modules
    signals.import_modules.send(sender=self.app)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/utils/dispatch/signal.py", line 166, in send
    response = receiver(signal=self, sender=sender, **named)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/fixups/django.py", line 69, in on_import_modules
    self.worker_fixup.validate_models()
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/kombu/utils/__init__.py", line 322, in __get__
    value = obj.__dict__[self.__name__] = self.__get(obj)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/fixups/django.py", line 64, in worker_fixup
    self._worker_fixup = DjangoWorkerFixup(self.app)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/fixups/django.py", line 99, in __init__
    self._cache = import_module('django.core.cache')
  File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/django/core/cache/__init__.py", line 69, in <module>
    if DEFAULT_CACHE_ALIAS not in settings.CACHES:
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/django/conf/__init__.py", line 54, in __getattr__
    self._setup(name)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/django/conf/__init__.py", line 49, in _setup
    self._wrapped = Settings(settings_module)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/django/conf/__init__.py", line 151, in __init__
    raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty.

【问题讨论】:

在主管配置中,尝试将密钥设置为'aa' 或任何简单的字符串并尝试 感谢您的建议,但这并没有解决问题。我更改了密钥值,重新启动了我的虚拟环境,执行“env | grep SECRET”以确认新的密钥,然后通过 Supervisor 重新启动 Celery,但仍然出现错误。 我的症状完全相同。将 supervisor 升级到 3.1.3 解决了这个问题。我从 apt 存储库中卸载了该版本并通过 pip 安装。 你有没有想过如何解决这个问题?我遇到了同样的问题,这让我发疯了 【参考方案1】:

在您的 celery 配置中,您需要指定您使用的设置。目前你有 prod.py 用于生产代码,所以你的 celery.py 应该是

# conf/celery.py
from __future__ import absolute_import
import os
from celery import Celery
from django.conf import settings
from conf import celeryconfig

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'conf.settings.prod')
app = Celery('conf')
app.config_from_object(celeryconfig)
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

因此 celery 会知道您要使用哪个设置文件(如果您在设置文件夹中有多个设置)

【讨论】:

以上是关于使用 Supervisor 启动 Celery 时如何避免 SECRET_KEY 错误?的主要内容,如果未能解决你的问题,请参考以下文章

Celery-Supervisor:如何重新启动主管工作以使新更新的 celery-tasks 工作?

Centos7 使用 Supervisor 守护进程 Celery

celery和supervisor配合使用,实现supervisor管理celery进程

python测试开发django-193.使用supervisord 后台启动celery 服务(worker/beat)

Celery,Tornado,Supervisor构建和谐的分布式系统

celery后台运行