使用Celery初始化带有参数的worker

时间:2014-11-21 21:16:13

标签: python celery

我遇到的问题似乎对我来说相对简单。

我正在使用Celery 3.1和Python 3,我想用参数初始化我的worker,以便他们可以使用这些细节进行设置。

具体来说:这些工作人员将消耗需要使用身份验证凭据与第三方API交互的任务。在执行任何任务之前,工作人员必须将身份验证详细信息传递给API服务器(身份验证详细信息在第一次身份验证请求后存储在Cookie中)。

我希望在从CLI启动时将这些登录凭据传递给worker。然后,我希望工作人员使用它们进行身份验证并存储会话以供将来使用时使用(理想情况下,这将存储在可从任务访问的属性中)。

Celery有可能吗?

作为旁注,我考虑将requests.session对象(来自Python requests库)作为任务参数传递,但这需要序列化,这看起来很不受欢迎。

2 个答案:

答案 0 :(得分:16)

我建议使用抽象的任务基类并缓存requests.session

来自Celery文档:

  

没有为每个请求实例化任务,但是在任务注册表中将任务注册为全局实例。

     

这意味着每个进程只会调用__init__构造函数一次,并且任务类在语义上更接近于Actor。

     

这对缓存资源也很有用......

import requests
from celery import Task

class APITask(Task):
    """API requests task class."""

    abstract = True

    # the cached requests.session object
    _session = None

    def __init__(self):
        # since this class is instantiated once, use this method
        # to initialize and cache resources like a requests.session
        # or use a property like the example below which will create
        # a requests.session only the first time it's accessed

    @property
    def session(self):
        if self._session is None:
            # store the session object for the first time
            session = requests.Session()
            session.auth = ('user', 'pass')

            self._session = session

        return self._session

现在,当您创建将发出API请求的任务时:

@app.task(base=APITask, bind=True)
def call_api(self, url):
    # self will refer to the task instance (because we're using bind=True)
    self.session.get(url)

此外,您可以使用app.task装饰器作为额外参数传递API身份验证选项,该参数将在任务的__dict__上设置,例如:

# pass a custom auth argument
@app.task(base=APITask, bind=True, auth=('user', 'pass'))
def call_api(self, url):
    pass

并使基类使用传递的身份验证选项:

class APITask(Task):
    """API requests task class."""

    abstract = True

    # the cached requests.session object
    _session = None

   # the API authentication
   auth = ()

    @property
    def session(self):
        if self._session is None:
            # store the session object for the first time
            session = requests.Session()
            # use the authentication that was passed to the task
            session.auth = self.auth

            self._session = session

        return self._session

您可以在Celery docs网站上阅读更多内容:

现在回到原来的问题,即从命令行向工作人员传递额外的参数:

Celery docs Adding new command-line options中有一节介绍此内容,这里是从命令行向用户传递用户名和密码的示例:

$ celery worker -A appname --username user --password pass

代码:

from celery import bootsteps
from celery.bin import Option


app.user_options['worker'].add(
    Option('--username', dest='api_username', default=None, help='API username.')
)

app.user_options['worker'].add(
    Option('--password', dest='api_password', default=None, help='API password.')
)


class CustomArgs(bootsteps.Step):

    def __init__(self, worker, api_username, api_password, **options):
        # store the api authentication
        APITask.auth = (api_username, api_password)


app.steps['worker'].add(CustomArgs)

答案 1 :(得分:0)

我认为您可以使用命令行参数调用您编写的脚本。如下所示:

my_script.py username password

在您的脚本中,您可以将主要功能包装在@celery.task@app.task装饰器中。

import sys

from celery import Celery

cel = Celery() # put whatever config info you need in here

@celery.task
def main():
    username, password = sys.argv[1], sys.argv[2]

这样的事情应该让你开始。一定要查看Python的argparse以获得更复杂的参数解析。