芹菜:为什么我需要经纪人来定期完成任务?

时间:2014-10-07 07:23:00

标签: python celery

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

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

从我读到的关于消息代理的内容来看,它们用于发送"信号"从一个正在运行的程序到另一个正在运行的程序。就像我有一段代码接受来自用户的电子邮件ID一样,它会将带有email-id的信号发送到另一段将发送电子邮件的代码。

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

3 个答案:

答案 0 :(得分:10)

Celery体系结构旨在跨多个服务器扩展和分配任务。对于像你这样的网站,这可能是一种过度杀伤力。通常需要队列服务来维护任务列表并发出已完成任务的状态。

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

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

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

答案 1 :(得分:2)

正如芹菜documentation所解释的那样:

  

Celery通过消息进行通信,通常使用经纪人在客户和工作人员之间进行调解。要启动任务,客户端会向队列添加一条消息,然后代理会将该消息传递给工作人员。

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

答案 2 :(得分: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)