Django - 设置预定的工作?

时间:2009-02-21 19:40:00

标签: python django web-applications scheduled-tasks

我一直在使用Django开发一个Web应用程序,我很好奇是否有办法安排作业定期运行。

基本上我只是想通过数据库运行并定期自动进行一些计算/更新,但我似乎找不到任何关于这样做的文档。

有谁知道如何设置它?

澄清:我知道我可以设置一个cron工作来完成这项工作,但我很好奇Django中是否有一些提供此功能的功能。我希望人们能够自己部署这个应用程序而无需进行太多配置(最好是零)。

我已经考虑通过简单地检查自上次将请求发送到网站后是否应该运行作业来“追溯”触发这些操作,但我希望有一些更清洁的东西。

25 个答案:

答案 0 :(得分:330)

我采用的一个解决方案是:

1)创建一个custom management command,例如

python manage.py my_cool_command

2)使用cron(在Linux上)或at(在Windows上)在所需的时间运行我的命令。

这是一个简单的解决方案,不需要安装繁重的AMQP堆栈。然而,使用像其他答案中提到的Celery这样的东西有很好的优势。特别是,使用Celery,不必将应用程序逻辑扩展到crontab文件中。但是,对于中小型应用程序而言,cron解决方案非常适用,并且您不需要很多外部依赖项。

编辑:

在Windows的更高版本中,不建议在Windows 8,Server 2012及更高版本中使用at命令。您可以使用schtasks.exe进行相同的使用。

答案 1 :(得分:137)

Celery是一个基于AMQP(RabbitMQ)构建的分布式任务队列。它还以类似cron的方式处理周期性任务(参见periodic tasks)。根据您的应用程序,它可能值得一玩。

使用django(docs)很容易设置Celery,并且在停机的情况下,定期任务实际上会跳过错过的任务。 Celery还有内置的重试机制,以防任务失败。

答案 2 :(得分:47)

我们开源了我认为的结构化应用程序。上面Brian的解决方案也提到了。会喜欢任何/所有反馈!

https://github.com/tivix/django-cron

它附带一个管理命令:

./manage.py runcrons

这就是工作。每个cron都被建模为一个类(因此它的所有OO)并且每个cron以不同的频率运行,并且我们确保相同的cron类型不会并行运行(如果crons本身需要比它们的频率更长的运行时间!)< / p>

谢谢!

答案 3 :(得分:36)

如果您使用的是标准POSIX OS,则使用cron

如果您使用的是Windows,则使用at

将Django管理命令写入

  1. 找出他们所处的平台。

  2. 为用户执行相应的“AT”命令,为您的用户更新crontab。

答案 4 :(得分:22)

有趣的新可插拔Django应用:django-chronograph

你只需要添加一个作为计时器的cron条目,你就可以在脚本中运行一个非常好的Django管理界面。

答案 5 :(得分:14)

看看Django Poor Man的Cron,它是一个Django应用程序,它使用spambots,搜索引擎索引机器人等,大致定期运行计划任务

请参阅:http://code.google.com/p/django-poormanscron/

答案 6 :(得分:9)

RabbitMQ和Celery比Cron拥有更多的功能和任务处理功能。如果任务失败不是问题,并且您认为您将在下次调用中处理损坏的任务,那么Cron就足够了。

芹菜&amp; AMQP将允许您处理已损坏的任务,并且它将由另一个工作人员(Celery工作人员监听下一个要处理的任务)再次执行,直到达到任务的max_retries属性。您甚至可以在失败时调用任务,例如记录失败,或者在达到max_retries后向管理员发送电子邮件。

当您需要扩展应用程序时,您可以分发Celery和AMQP服务器。

答案 7 :(得分:9)

Brian Neal关于通过cron运行管理命令的建议很有效,但是如果你正在寻找一些更强大的东西(但不像Celery那么精细),我会调查像Kronos这样的库:< / p>
# app/cron.py

import kronos

@kronos.register('0 * * * *')
def task():
    pass

答案 8 :(得分:8)

我个人使用cron,但Jobs Schedulingdjango-extensions部分看起来很有趣。

答案 9 :(得分:7)

前一段时间我的要求完全相同,最后使用APSchedulerUser Guide)来解决问题

它使调度作业变得非常简单,并使其与某些代码的基于请求的执行保持独立。以下是我在代码中使用的一个简单示例。

from apscheduler.schedulers.background import BackgroundScheduler

scheduler = BackgroundScheduler()
job = None

def tick():
    print('One tick!')\

def start_job():
    global job
    job = scheduler.add_job(tick, 'interval', seconds=3600)
    try:
        scheduler.start()
    except:
        pass

希望这有助于某人!

答案 10 :(得分:6)

我只想到了这个相当简单的解决方案:

  1. 定义视图函数 do_work(req,param),就像使用任何其他视图一样,使用URL映射,返回HttpResponse等等。
  2. 使用您的计时首选项(或使用Windows中的AT或计划任务)设置一个cron作业,该计划运行 curl http://localhost/your/mapped/url?param=value
  3. 您可以添加参数,只需在URL中添加参数即可。

    告诉我你们的想法。

    [更新] 我现在使用来自django-extensions的runjob命令而不是curl。

    我的cron看起来像这样:

    @hourly python /path/to/project/manage.py runjobs hourly
    

    ......等等每日,每月等等。您也可以将其设置为运行特定作业。

    我发现它更容易管理,更清洁。不需要将URL映射到视图。只需定义你的工作类和crontab就可以了。

答案 11 :(得分:6)

将以下内容放在cron.py文件的顶部:

#!/usr/bin/python
import os, sys
sys.path.append('/path/to/') # the parent directory of the project
sys.path.append('/path/to/project') # these lines only needed if not on path
os.environ['DJANGO_SETTINGS_MODULE'] = 'myproj.settings'

# imports and code below

答案 12 :(得分:6)

虽然不是Django的一部分,Airflow是一个更新的项目(截至2016年),对任务管理很有用。

Airflow是一个工作流程自动化和计划系统,可用于创作和管理数据管道。基于Web的UI为开发人员提供了一系列用于管理和查看这些管道的选项。

Airflow是用Python编写的,使用Flask构建。

Airflow由Airimeb的Maxime Beauchemin创建,于2015年春季开源。它于2016年冬季加入了Apache Software Foundation的孵化计划。以下是Git project page和一些补充background information

答案 13 :(得分:4)

在代码部分之后,我可以编写任何内容,就像我的views.py:)

#######################################
import os,sys
sys.path.append('/home/administrator/development/store')
os.environ['DJANGO_SETTINGS_MODULE']='store.settings'
from django.core.management impor setup_environ
from store import settings
setup_environ(settings)
#######################################

http://www.cotellese.net/2007/09/27/running-external-scripts-against-django-models/

答案 14 :(得分:3)

用于调度程序作业的Django APScheduler。 Advanced Python Scheduler(APScheduler)是一个Python库,可让您安排Python代码稍后执行,一次或定期执行。您可以根据需要动态添加或删除旧作业。

注意:我是该库的作者

安装APScheduler

pip install apscheduler

查看要调用的文件功能

文件名:scheduler_jobs.py

def FirstCronTest():
    print("")
    print("I am executed..!")

配置调度程序

制作execute.py文件并添加以下代码

from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()

您编写的函数在这里,调度程序函数写在scheduler_jobs

import scheduler_jobs 

scheduler.add_job(scheduler_jobs.FirstCronTest, 'interval', seconds=10)
scheduler.start()

链接文件以执行

现在,在Url文件底部添加以下行

import execute

答案 15 :(得分:3)

您绝对应该检查django-q! 它不需要任何额外的配置,并且很可能具有处理商业项目中任何生产问题所需的一切。

它是积极开发的,并且与django,django ORM,mongo,redis很好地集成在一起。这是我的配置:

# django-q
# -------------------------------------------------------------------------
# See: http://django-q.readthedocs.io/en/latest/configure.html
Q_CLUSTER = {
    # Match recommended settings from docs.
    'name': 'DjangoORM',
    'workers': 4,
    'queue_limit': 50,
    'bulk': 10,
    'orm': 'default',

# Custom Settings
# ---------------
# Limit the amount of successful tasks saved to Django.
'save_limit': 10000,

# See https://github.com/Koed00/django-q/issues/110.
'catch_up': False,

# Number of seconds a worker can spend on a task before it's terminated.
'timeout': 60 * 5,

# Number of seconds a broker will wait for a cluster to finish a task before presenting it again. This needs to be
# longer than `timeout`, otherwise the same task will be processed multiple times.
'retry': 60 * 6,

# Whether to force all async() calls to be run with sync=True (making them synchronous).
'sync': False,

# Redirect worker exceptions directly to Sentry error reporter.
'error_reporter': {
    'sentry': RAVEN_CONFIG,
},
}

答案 16 :(得分:2)

是的,上面的方法太棒了。我尝试了其中一些。最后,我发现了一个这样的方法:

    from threading import Timer

    def sync():

        do something...

        sync_timer = Timer(self.interval, sync, ())
        sync_timer.start()

就像递归

好的,我希望这种方法可以满足您的要求。 :)

答案 17 :(得分:2)

今天我和你的问题有类似的东西。

我不想让它由服务器trhough cron处理(并且大多数libs最终只是cron助手)。

所以我创建了一个调度模块并将其附加到 init

这不是最好的方法,但它帮助我将所有代码放在一个地方,并使其执行与主应用程序相关。

答案 18 :(得分:2)

更现代的解决方案(与Celery相比)是Django Q: https://django-q.readthedocs.io/en/latest/index.html

它有很棒的文档,很容易理解。 Windows支持缺乏,因为Windows不支持进程分叉。但是如果使用Windows for Linux子系统创建开发环境,它可以正常工作。

答案 19 :(得分:1)

我不确定这对任何人都有用,因为我必须提供系统的其他用户来安排作业,而不让他们访问实际的服务器(windows)任务计划程序,我创建了这个可重用的应用程序。 / p>

请注意,用户可以访问服务器上的一个共享文件夹,他们可以在其中创建所需的命令/任务/ .bat文件。然后可以使用此应用程序安排此任务。

应用名称为Django_Windows_Scheduler

截图: enter image description here

答案 20 :(得分:1)

我用芹菜来创造我的周期性任务。首先,您需要按如下方式安装它:

pip install django-celery

不要忘记在您的设置中注册django-celery,然后您可以执行以下操作:

from celery import task
from celery.decorators import periodic_task
from celery.task.schedules import crontab
from celery.utils.log import get_task_logger
@periodic_task(run_every=crontab(minute="0", hour="23"))
def do_every_midnight():
 #your code

答案 21 :(得分:0)

如果您想要比 Celery 更强大可靠,请尝试在 AWS SQS / SNS 之上构建 TaskHawk 强>

参考:http://taskhawk.readthedocs.io

答案 22 :(得分:0)

对于简单的dockerized项目,我真的看不到任何现有的答案。

因此,我写了一个非常准系统的解决方案,不需要外部库或触发器,它们可以独立运行。不需要外部os-cron,应该在每种环境下都可以工作。

它通过添加中间件来工作:middleware.py

import threading

def should_run(name, seconds_interval):
    from application.models import CronJob
    from django.utils.timezone import now

    try:
        c = CronJob.objects.get(name=name)
    except CronJob.DoesNotExist:
        CronJob(name=name, last_ran=now()).save()
        return True

    if (now() - c.last_ran).total_seconds() >= seconds_interval:
        c.last_ran = now()
        c.save()
        return True

    return False


class CronTask:
    def __init__(self, name, seconds_interval, function):
        self.name = name
        self.seconds_interval = seconds_interval
        self.function = function


def cron_worker(*_):
    if not should_run("main", 60):
        return

    # customize this part:
    from application.models import Event
    tasks = [
        CronTask("events", 60 * 30, Event.clean_stale_objects),
        # ...
    ]

    for task in tasks:
        if should_run(task.name, task.seconds_interval):
            task.function()


def cron_middleware(get_response):

    def middleware(request):
        response = get_response(request)
        threading.Thread(target=cron_worker).start()
        return response

    return middleware

models/cron.py

from django.db import models


class CronJob(models.Model):
    name = models.CharField(max_length=10, primary_key=True)
    last_ran = models.DateTimeField()

settings.py

MIDDLEWARE = [
    ...
    'application.middleware.cron_middleware',
    ...
]

答案 23 :(得分:0)

简单的方法是编写一个自定义的shell命令,请参见Django Documentation并在Linux上使用cronjob执行它。但是我强烈建议使用像RabbitMQ这样的消息代理以及芹菜。也许你可以看看 这个Tutorial

答案 24 :(得分:0)

另一个选项是simple-scheduler。它在后台运行,因此可以轻松与任何应用程序集成。查看示例 here

烧瓶示例:

if __name__ == "__main__":
    try:
        scheduled_jobs.run()
        application.run(host='0.0.0.0', port=5000)
    except Exception as e:
        # log them