如何使用django-background-tasks

时间:2015-06-13 07:21:43

标签: python django background-task

我正在制作django应用程序。要根据行和注释计算Feed的排名,我正在尝试使用django-background-tasks。我在节点模型中使用的函数是:

{{1}}

但我没有看到任何分数变化。这意味着我正在以正确的方式做到这一点,我错过了基本概念。有人可以告诉我如何使用django-background-tasks安排任务或引用我现有的文档。

4 个答案:

答案 0 :(得分:2)

django-background-task和django-background-task s 之间存在差异。 django-background-task没有维护,与较新的Django版本不兼容。我们不久前更新并扩展了新功能,并在Github上维护了新的向后兼容软件包django-background-task s 。可以从PyPI下载或安装新的django-background-tasks应用程序。

答案 1 :(得分:2)

由于这个问题似乎很笼统,我相信根据我的个人经验,这里是有关“如何使用django-background-tasks”的快速备忘单的正确位置。希望我不会成为唯一使用它的人:)

环境

  • Python 3.8
  • Django 3.1

安装

我喜欢pipenv,所以:

> cd [my-django-project root directory]
> pipenv install django-background-tasks

现在将 task添加到 settings.py 中的INSTALLED_APPS:

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

并执行数据库迁移,以确保django-background-tasks模式已就位:

> pipenv shell
(my-django-project) bash-3.2$  python manage.py migrate

创建和注册任务

任何Python函数都可以成为一项任务,我们只需要应用 @background 批注将其注册为这样:

from background_task import background

@background(schedule=10)
def do_something(s1: str, s1: str) -> None:
   """
   Does something that takes a long time
   :param p1: first parameter
   :param p2: second parameter
   :return: None
   """
   pass

现在,我们可以像往常一样在项目中调用该函数了:

do_something("first parameter", "second parameter")

重要的是要注意,调用该函数并不会实际执行其代码;而是通过“ django-background-tasks”模块将任务记录存储到数据库中,更确切地说是将其存储到“ background_task”表中。因此,编写返回某事的任务函数几乎没有用,因为无论如何该任务都将在稍后的时刻在后台执行,因此该函数在调用时返回的“值”几乎没有意义。 。我看到的唯一用于返回值的用例是出于测试目的,请参阅下面的测试任务部分。

处理任务

为了实际运行已注册的任务,我们必须使用以下管理命令:

> python manage.py process_tasks

请参考module's documentation,以获取命令选项的说明。 正如其他用户已经指出的那样,通常将此命令包装在cron作业中以确保定期处理任务。在这种情况下, duration 选项可能很有用:它表示process_task命令保持运行的秒数。默认情况下,持续时间为0,这意味着“永远运行”,但是在我看来,这是非常危险的,因为如果由于某种原因命令崩溃或被中断,您的任务将不再被处理,并且可能需要很长时间才能通过你意识到了。

更好的方法是将持续时间设置为明确定义的时间,例如15分钟,然后将cron作业配置为每15分钟运行一次以重新启动处理命令。这样,如果命令崩溃,无论如何以后cron作业都会重新启动它。

测试任务

通过“ process_tasks”管理命令测试任务非常糟糕,为此,我们应该坚持使用Python unittest模块,这也是“ Django方式”。

我当然不会在本文中讨论 unittest ,我只想指出,在单元测试期间,您希望像通常一样以同步方式执行功能Python功能。的语法如下:

do_something.now("first parameter", "second parameter")

修饰符“ now”运行该函数并等待其终止。这是我认为返回值有用的唯一用例。有了返回值,您就可以使用 unittest 提供的“ assert *”功能的全部功能。

检查任务是否已在运行

有时候,您可能不希望同一任务多次运行。例如,我经常使用后台任务来训练机器学习模型,这需要很多时间。为了避免弄乱我的数据,我宁愿确保在上一个模型完成之前,不能在同一模型上启动另一个训练任务。

为此,我必须在开始新任务之前检查该任务是否已在运行;但是如何唯一地识别任务?对我来说,简单的方法是为任务分配一个“ verbose_name”,可以在计划任务时完成:

do_something("first parameter", "second parameter", verbose_name="my_task_verbose_name")

现在,如果我想检查此任务是否已经在运行,我可以简单地读取 background_task 表并确认其中没有具有相同“冗长名称”的任务。利用“ django-background-tasks”本身提供的 Task 模型可以很容易地做到这一点:

from background_task.models import Task

tasks = Task.objects.filter(verbose_name="my_task_verbose_name")
if len(tasks) == 0:
    # no task running with this name, go ahead!
    pass
else:
    # task already running
    pass

不用说,我们必须确保分配给我们任务的冗长名称是唯一的。

进一步阅读

Django Background Tasks documentation

答案 2 :(得分:1)

您应该按照here所述运行python manage.py process_tasks。您可以将其添加到crontab以定期执行。

UPD:

  1. 您不需要使用crontab运行process_tasks因为此命令每5秒内部睡眠一次(此值可配置),然后再次检查是否有任何任务要运行。
  2. 你的任务看起来很奇怪。您应该在单独的文件中将其声明为全局函数,并在其中传递id模型,通过id获取对象进行计算并保存您的对象。

答案 3 :(得分:1)

你似乎以错误的方式使用它。

假设您必须执行某项特定任务,请在用户注册后5分钟发送邮件。那么你做的是:

使用django-background-task创建任务。

@background(schedule=60*5)
def send_html_mail_post(id, template):
    u = User.objects.get(id=id)
    user_email = u.email
    subject = "anything"
    html_content = template.format(arguments)
    from_email, to = from_email, user_email
    text_content = ''
    msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
    msg.attach_alternative(html_content, "text/html")
    msg.send()

顶部的装饰器定义了调用函数的时间是实际事件发生的时间。

在您需要时拨打电话。

def create_user_profile(sender, instance, created, **kwargs):
    if created:
        up = UserProfile.objects.create(user=instance)
        up.save()
        tasks.send_welcome_email(up.user.id, template=template)

这将创建任务并将其保存在数据库中,并在db中存储它将被执行的时间。

您想要做的事情,定期做某事,通过创建cron作业可以更轻松地完成。

你做的是,你创建了一个你在问题中显示的功能。然后定义一个cron作业,每5分钟或任何你想要的间隔调用它。