563

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

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

有谁知道如何设置这个?

澄清一下:我知道我可以设置一个cron工作来做到这一点,但我很好奇 Django 中是否有一些特性可以提供这个功能。我希望人们能够自己部署这个应用程序,而不必做太多配置(最好是零)。

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

4

24 回答 24

393

我采用的一种解决方案是这样做:

1)创建自定义管理命令,例如

python manage.py my_cool_command

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

这是一个简单的解决方案,不需要安装繁重的 AMQP 堆栈。但是,使用其他答案中提到的芹菜之类的东西有很多好处。特别是,使用 Celery 时,不必将应用程序逻辑分散到 crontab 文件中是一件好事。但是,cron 解决方案非常适合中小型应用程序,并且您不希望有很多外部依赖项。

编辑:

在更高版本的 Windows 中at,Windows 8、Server 2012 及更高版本已弃用该命令。您可以schtasks.exe用于相同的用途。

**** 更新 **** 这是 django doc 的新链接,用于编写自定义管理命令

于 2009-02-21T20:06:38.010 回答
166

Celery是一个分布式任务队列,建立在 AMQP (RabbitMQ) 之上。它还以类似 cron 的方式处理周期性任务(请参阅周期性任务)。根据您的应用程序,可能值得一试。

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

于 2009-06-29T11:56:47.943 回答
54

我们已经开源了我认为的结构化应用程序。布赖恩的上述解决方案也暗示了这一点。我们会喜欢任何/所有反馈!

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

它带有一个管理命令:

./manage.py runcrons

这就是工作。每个 cron 都被建模为一个类(所以它都是面向对象的)并且每个 cron 以不同的频率运行,我们确保相同的 cron 类型不会并行运行(以防 cron 本身的运行时间比它们的频率长!)

于 2012-01-30T21:47:06.483 回答
38

如果您使用的是标准 POSIX 操作系统,则使用cron

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

写一个 Django 管理命令到

  1. 弄清楚他们在哪个平台上。

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

于 2009-02-21T20:04:40.260 回答
23

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

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

于 2009-03-07T08:32:30.637 回答
16

看看 Django Poor Man's Cron,这是一个 Django 应用程序,它利用垃圾邮件机器人、搜索引擎索引机器人等以大约固定的时间间隔运行计划任务

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

于 2009-02-21T20:29:47.643 回答
12

前段时间我有完全相同的要求,最终使用APScheduler用户指南)解决了它

它使调度作业变得超级简单,并使其独立于基于请求的某些代码的执行。下面是一个简单的例子。

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

希望这对某人有帮助!

于 2017-06-22T14:04:20.800 回答
10

Brian Neal 建议通过 cron 运行管理命令效果很好,但如果您正在寻找更强大的东西(但不像 Celery 那样精致),我会研究像Kronos这样的库:

# app/cron.py

import kronos

@kronos.register('0 * * * *')
def task():
    pass
于 2011-12-20T12:30:42.837 回答
10

用于调度程序作业的 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
于 2019-09-19T21:03:41.100 回答
9

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

Celery & AMQP会让你处理被破坏的任务,它会被另一个工作人员再次执行(芹菜工作人员监听下一个要处理的任务),直到max_retries达到任务的属性。您甚至可以在失败时调用任务,例如记录失败,或max_retries在达到目标后向管理员发送电子邮件。

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

于 2012-04-03T14:54:18.513 回答
8

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

于 2009-02-22T03:18:07.553 回答
7

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

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

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

Airflow 由 Airbnb 的 Maxime Beauchemin 创建并于 2015 年春季开源。它于 2016 年冬季加入 Apache 软件基金会的孵化计划。这是Git 项目页面和一些附加背景信息

于 2016-07-19T20:49:43.057 回答
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
于 2010-01-07T23:26:10.873 回答
6

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

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

您可以添加参数,但只需将参数添加到 URL。

告诉我你们的想法。

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

我的 cron 看起来像这样:

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

... 以此类推,适用于每日、每月等。您还可以将其设置为运行特定作业。

我发现它更易于管理和更清洁。不需要将 URL 映射到视图。只需定义您的工作类别和 crontab 即可。

于 2011-10-30T13:19:58.790 回答
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/

于 2011-05-17T03:09:13.127 回答
4

你一定要看看 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,
},
}
于 2018-08-04T05:50:24.100 回答
3

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

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

于 2017-11-11T16:38:15.553 回答
2

我今天遇到了类似你的问题。

我不想让服务器通过 cron 处理它(大多数库最终只是 cron 助手)。

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

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

于 2011-09-02T18:41:33.843 回答
2

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

    from threading import Timer

    def sync():

        do something...

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

就像递归一样。

好的,我希望这个方法能满足你的要求。:)

于 2014-03-26T01:04:36.933 回答
1

我使用 celery 来创建我的定期任务。首先,您需要按如下方式安装它:

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
于 2015-08-31T21:52:36.653 回答
1

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

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

应用名称是Django_Windows_Scheduler

截屏: 在此处输入图像描述

于 2017-01-11T19:34:28.060 回答
0

如果您想要比Celery可靠的东西,请尝试构建在AWS SQS/SNS之上的TaskHawk

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

于 2018-05-21T23:53:52.680 回答
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',
    ...
]
于 2019-01-25T12:13:05.980 回答
0

简单的方法是编写自定义 shell 命令,参见Django 文档并在 linux 上使用 cronjob 执行它。但是我强烈推荐使用像 RabbitMQ 这样的消息代理和 celery。也许你可以看看这个教程

于 2019-02-20T10:21:02.703 回答