【问题标题】:Celery: why do I need a broker for periodic tasks?Celery:为什么我需要经纪人来执行定期任务?
【发布时间】:2014-12-01 13:31:37
【问题描述】:

我有一个独立脚本,它可以抓取页面、启动与数据库的连接并将数据库写入其中。我需要它在 x 小时后定期执行。我可以使用 bash 脚本和伪代码来实现:

while true
do
  python scraper.py
  sleep 60*60*x
done

根据我所读到的消息代理,它们用于从一个正在运行的程序向另一个程序发送“信号”,原则上类似于 HTTP。就像我有一段代码接受来自用户的电子邮件 ID 一样,它将带有电子邮件 ID 的信号发送到另一段将发送电子邮件的代码。

我需要 celery 在 heroku 上运行定期任务。我已经在单独的服务器上有一个 mongodb。为什么我需要为rabbitmq或redis运行另一个服务器只是为了这个?我可以在没有经纪人的情况下使用 celery 吗?

【问题讨论】:

    标签: python celery celery-broker


    【解决方案1】:

    对于这样的应用,最好使用Django Background Tasks

    安装 从 PyPI 安装:

    pip install django-background-tasks
    

    添加到 INSTALLED_APPS:

    INSTALLED_APPS = (
        # ...
        'background_task',
        # ...
    )
    

    迁移您的数据库:

    python manage.py makemigrations background_task
    python manage.py migrate
    

    创建和注册任务

    要注册任务,请使用背景装饰器:

    from background_task import background
    from django.contrib.auth.models import User
    
    @background(schedule=60)
    def notify_user(user_id):
        # lookup user by id and send them a message
        user = User.objects.get(pk=user_id)
        user.email_user('Here is a notification', 'You have been notified')
    

    这会将 notify_user 转换为后台任务函数。当您从常规代码中调用它时,它实际上会创建一个 Task 对象并将其存储在数据库中。然后,数据库包含有关稍后实际需要运行的函数的序列化信息。这确实限制了调用函数时可以传递的参数——它们都必须可序列化为 JSON。因此,为什么在上面的示例中传递的是 user_id 而不是 User 对象。

    正常调用 notify_user 将安排原始函数在 60 秒后运行:

    notify_user(user.id)
    

    这是默认的调度时间(在装饰器中设置),但它可以被覆盖:

    notify_user(user.id, schedule=90) # 90 seconds from now
    notify_user(user.id, schedule=timedelta(minutes=20)) # 20 minutes from now
    notify_user(user.id, schedule=timezone.now()) # at a specific time
    

    您也可以立即在同步模式下运行原始功能:

    notify_user.now(user.id)   # launch a notify_user function and wait for it
    notify_user = notify_user.now   # revert task function back to normal function. 
    

    对测试很有用。 您可以在调度任务时指定详细名称和创建者:

     notify_user(user.id, verbose_name="Notify user", creator=user)
    

    【讨论】:

      【解决方案2】:

      Celery 架构旨在跨多个服务器扩展和分配任务。对于像您这样的网站,这可能是一种矫枉过正。通常需要队列服务来维护任务列表并指示已完成任务的状态。

      您可能想看看 Huey。 Huey is small-scale Celery "Clone" needing only Redis as an external dependency,不是 RabbitMQ。它仍然使用 Redis 队列机制来排列队列中的任务。

      还有Advanced Python scheduler,它甚至不需要Redis,但可以在内存中保持队列的状态。

      或者,如果您有非常少量的定期任务,没有延迟任务,我会使用 Cron 和纯 Python 脚本来运行任务。

      【讨论】:

      • Celery Python如何使用MySQL数据库?
      • @OPV 请为此打开一个新问题,因为 Celery 文档没有涵盖它
      【解决方案3】:

      正如 Celery documentation 解释的那样:

      Celery 通过消息进行通信,通常使用代理在客户端和工作人员之间进行调解。为了启动任务,客户端将消息添加到队列中,然后代理将消息传递给工作人员。

      您可以使用现有的 MongoDB 数据库作为代理。见Using MongoDB

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-25
        • 2020-04-05
        • 1970-01-01
        • 2012-03-15
        • 1970-01-01
        • 2020-11-03
        • 1970-01-01
        • 2012-02-13
        相关资源
        最近更新 更多