关于python:django-设置一个预定的作业?

Django - Set Up A Scheduled Job?

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

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

有人知道怎么设置这个吗?

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

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


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

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

1
python manage.py my_cool_command

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

这是一个简单的解决方案,不需要安装大量的AMQP堆栈。不过,在其他答案中提到,使用芹菜这样的食物有很多好处。特别是,对于芹菜,最好不要将应用程序逻辑分散到crontab文件中。然而,cron解决方案非常适合中小型应用程序,并且您不需要太多外部依赖项。

编辑:

在Windows的较新版本中,不推荐在Windows 8、Server 2012及更高版本中使用at命令。您可以将schtasks.exe用于相同的用途。


芹菜是一个分布式任务队列,构建在AMQP(rabbitmq)上。它还以类似cron的方式处理定期任务(参见定期任务)。取决于你的应用程序,它可能值得一个甘德。

芹菜很容易与Django(docs)一起设置,并且定期任务实际上会在停机时跳过错过的任务。芹菜还有内置的重试机制,以防任务失败。


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

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

它附带一个管理命令:

1
./manage.py runcrons

这就是工作。每个cron都被建模为一个类(因此它的全部OO),并且每个cron以不同的频率运行,并且我们确保相同的cron类型不会并行运行(以防cron自身的运行时间比其频率长!)

谢谢!


如果您使用的是标准的POSIX操作系统,那么就使用cron。

如果使用的是Windows,则使用的是。

将django管理命令写入

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

  • 或者为用户执行适当的"at"命令,或者为用户更新crontab。


  • 有趣的新可插拔django应用程序:django计时手表

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


    看看Django Poor-Man的cron,它是一个Django应用程序,利用Spambots、搜索引擎索引机器人和类似工具,以大约有规律的间隔运行计划任务。

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


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

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

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


    Brian Neal建议通过cron运行管理命令,效果很好,但是如果你想找一个更健壮(但不如芹菜那么精致)的东西,我会找一个类似kronos的库:

    1
    2
    3
    4
    5
    6
    7
    # app/cron.py

    import kronos

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

    我个人使用cron,但是django扩展的工作调度部分看起来很有趣。


    不久前我有了完全相同的需求,最终使用apscheduler(用户指南)解决了它。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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

    希望这能帮助别人!


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

    1
    2
    3
    4
    5
    6
    7
    #!/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

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

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

    气流是用python编写的,使用烧瓶构建。

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


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

  • 定义一个视图函数Do_Work(req,param),就像对任何其他视图一样,通过URL映射,返回一个httpResponse等等。
  • 使用计时首选项(或在Windows中使用at或scheduled tasks)设置cron作业,该作业运行curl http://localhost/your/mapped/url?PARAM=值。
  • 您可以添加参数,但只需向URL添加参数。

    告诉我你们怎么想。

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

    我的克罗恩长得像这样:

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

    …每天、每月等等。您还可以将其设置为运行特定作业。

    我觉得它更容易管理,更干净。不需要将URL映射到视图。只需定义作业类和crontab,就可以设置。


    在代码部分之后,我可以编写任何类似于我的views.py:)的内容。

    1
    2
    3
    4
    5
    6
    7
    8
    #######################################
    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/


    你一定要看看姜戈-Q!它不需要额外的配置,很可能拥有处理商业项目中任何生产问题所需的一切。

    它积极开发,并与Django、Django ORM、Mongo、Redis很好地集成。以下是我的配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    # 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,
    },
    }

    是的,上面的方法太好了。我试了一些。最后,我找到了这样一种方法:

    1
    2
    3
    4
    5
    6
    7
    8
        from threading import Timer

        def sync():

            do something...

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

    就像递归一样。

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


    一个更现代的解决方案(与芹菜相比)是姜戈Q:https://django-q.readthedocs.io/en/latest/index.html网站

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


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

    我不想让服务器用cron来处理它(大多数lib最终只是cron助手)。

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

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


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

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

    应用程序名为django_Windows_Scheduler

    截图:enter image description here


    我用芹菜做我的定期工作。首先,您需要如下安装:

    1
    pip install django-celery

    不要忘记在您的设置中注册django-celery,然后您可以这样做:

    1
    2
    3
    4
    5
    6
    7
    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


    简单的方法是编写一个定制的shell命令,参见django文档,并在Linux上使用cronjob执行它。不过,我强烈建议使用像rabbitmq这样的消息代理和芹菜。也许你可以看看本教程


    如果你想要比芹菜更可靠的东西,试试建立在AWS SQS/SNS之上的TaskHawk。

    请参阅:http://taskhawk.readthedocs.io


    对于简单的码头化项目,我真的看不到任何现有的答案适合。

    因此,我编写了一个非常简单的解决方案,不需要外部库或触发器,它们自己运行。不需要外部操作系统cron,应该可以在每个环境中工作。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    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

    1
    2
    3
    4
    5
    6
    from django.db import models


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

    settings.py

    1
    2
    3
    4
    5
    MIDDLEWARE = [
        ...
        'application.middleware.cron_middleware',
        ...
    ]