【问题标题】:Python Key Error when setting environment variable in supervisord在supervisord中设置环境变量时出现Python键错误
【发布时间】:2015-04-25 03:30:37
【问题描述】:

我在 supervisord 中设置了一个环境变量:

[program:worker]
directory = /srv/app/
command=celery -A tasks worker -Q default -l info -n default_worker.%%h
environment=BROKER="amqp://admin:password@xxxxx:5672//"

在我的 celeryconfig.py 中,然后我尝试像这样读取该变量。

BROKER = os.environ['BROKER']

但我还是得到了下面错误的关键,为什么?

  File "/usr/local/lib/python2.7/dist-packages/celery/loaders/base.py", line 106, in import_module
    return importlib.import_module(module, package=package)
  File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
  File "/srv/app/celeryconfig.py", line 6, in <module>
    BROKER = os.environ['BROKER']
  File "/usr/lib/python2.7/UserDict.py", line 23, in __getitem__
    raise KeyError(key)
KeyError: 'BROKER

如 cmets 中所建议的,有一个环境文件转储:

{
    'SUPERVISOR_GROUP_NAME': 'celery_default_worker',
    'TERM': 'linux',
    'SUPERVISOR_SERVER_URL': 'unix: ///var/run/supervisor.sock',
    'UPSTART_INSTANCE': '',
    'RUNLEVEL': '2',
    'UPSTART_EVENTS': 'runlevel',
    'PREVLEVEL': 'N',
    'SUPERVISOR_PROCESS_NAME': 'celery_default_worker',
    'UPSTART_JOB': 'rc',
    'PWD': '/',
    'SUPERVISOR_ENABLED': '1',
    'runlevel': '2',
    'PATH': '/usr/local/sbin: /usr/local/bin: /sbin: /bin: /usr/sbin: /usr/bin',
    'previous': 'N'
}

【问题讨论】:

  • 奇怪 - 第一次看起来确实正确。将with open("/tmp/celery-environment.txt", "w") as f: f.write(repr(os.environ)) 添加到celeryconfig.py,然后检查/tmp/celery-environment.txt 文件以查看您的环境中的是什么,这可能有助于您的调试?
  • 确认执行顺序。即检查是否首先在supervisord: 中设置环境变量BROKER 或在CeleryConfig.py 中首先读取BROKER。如果先读取CeleryConfig.py,则不存在BROKER,因为在supervisord:中设置了BROKER
  • 您是否告诉supervisord 接受更改,或者重新启动supervisord
  • 另外,还有这个错误:github.com/Supervisor/supervisor/issues/91github.com/Supervisor/supervisor/pull/550 请检查您的 supervisord 版本,以了解这些补丁何时被接受。
  • @qarma:只有在环境变量值部分有空格或其他元值时才需要引用。

标签: python django celery supervisord


【解决方案1】:

这看起来像是supervisord 中的一个已知错误:

http://github.com/Supervisor/supervisor/issues/91(已解决)

http://github.com/Supervisor/supervisor/pull/550(待定)

在这种情况下,将您的环境规范移动到全局范围(对于 supervisord 进程本身)可能是一个可接受的解决方法。

最后,如果所有其他方法都失败了,请将 celery 包装在一个接受此特定环境变量作为命令行参数的 shell 脚本中。

【讨论】:

    【解决方案2】:

    这个答案很可能不是原因,请查看 https://stackoverflow.com/a/28829162/1589147 以获取有关 supervisord 相关错误的信息。

    我可以部分重现您的错误。当 celery 在主管中运行时,我没有看到错误。当我尝试从未设置 BROKER 环境变量的主管之外的环境中运行任务时,我看到了错误。 celeryconfig.py 由 celery 和任何试图执行任务的东西执行。

    我不确定这个问题是否正是您遇到的问题,您是否可以分享您执行任务的方式以及何时引发该异常可能会有所帮助。

    例如,如果我尝试从 ipython 运行任务,则会生成与您的错误匹配的错误。

    In [1]: from tasks import add
    In [2]: add.delay(2,3)
    ...
         21         if hasattr(self.__class__, "__missing__"):
         22             return self.__class__.__missing__(self, key)
    ---> 23         raise KeyError(key)
         24     def __setitem__(self, key, item): self.data[key] = item
         25     def __delitem__(self, key): del self.data[key]
    
    KeyError: 'BROKER'
    

    celeryconfig.py 在本地加载,以便建立与 celery 代理和后端的连接。如果不设置 BROKER 环境变量,我将无法执行任务。

    如果我在执行任务之前设置环境变量,同样的代码也适用于我。

    In [3]: import os
    In [4]: os.environ["BROKER"] = "broker is set"
    In [5]: add.delay(2,3)
    Out[5]: <AsyncResult: 0f3xxxx-87fa-48d7-9258-173bdd2052ca>
    

    这是我使用的文件,以防万一。

    supervisor.conf:supervisord -c supervisor.conf

    [unix_http_server]
    file=/tmp/supervisor.sock
    
    [supervisord]
    loglevel = info
    nodaemon = true
    identifier = supervisor
    
    [supervisorctl]
    serverurl=unix:///tmp/supervisor.sock
    
    [rpcinterface:supervisor]
    supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
    
    [program:worker]
    command=/app/srv/main-env/bin/celery -A tasks worker -Q default -l info -n default_worker.%%h
    environment=BROKER="amqp://admin:password@xxxxx:5672//"
    directory=/app/srv/
    numprocs=1
    stdout_logfile=/app/srv/worker.log
    stderr_logfile=/app/srv/worker.log
    autostart=true
    autorestart=true
    startsecs=10
    stopwaitsecs = 600
    killasgroup=true
    priority=998
    

    celeryconfig.py:

    import os
    
    
    BROKER = os.environ['BROKER']
    

    tasks.py:

    from celery import Celery
    
    app = Celery(
        'tasks',
        backend='amqp',
        broker='amqp://admin:password@xxxxx:5672//')
    app.config_from_object('celeryconfig')
    
    
    @app.task
    def add(x, y):
            return x + y
    

    【讨论】:

    • 看起来supervisord 未能应用子进程环境变量。
    • 我认为您提到的错误比我的回答更可能是报告错误的原因,因为它们显示的环境显示了许多主管设置的环境变量。您介意发表您的评论作为答案,以便我投票吗?
    猜你喜欢
    • 2014-08-05
    • 1970-01-01
    • 2012-06-08
    • 1970-01-01
    • 1970-01-01
    • 2014-12-03
    • 1970-01-01
    • 2017-11-13
    • 2021-12-27
    相关资源
    最近更新 更多