Einen geplanten Job einrichten?


519

Ich habe mit Django an einer Web-App gearbeitet und bin gespannt, ob es eine Möglichkeit gibt, einen Job so zu planen, dass er regelmäßig ausgeführt wird.

Grundsätzlich möchte ich nur die Datenbank durchgehen und regelmäßig einige Berechnungen / Aktualisierungen vornehmen, aber ich kann anscheinend keine Dokumentation dazu finden.

Weiß jemand, wie man das einrichtet?

Zur Verdeutlichung: Ich weiß, dass ich einen cronJob dafür einrichten kann , aber ich bin gespannt, ob es in Django eine Funktion gibt, die diese Funktionalität bietet. Ich möchte, dass die Benutzer diese App selbst bereitstellen können, ohne viel konfigurieren zu müssen (vorzugsweise null).

Ich habe überlegt, diese Aktionen "rückwirkend" auszulösen, indem ich einfach überprüfe, ob ein Job seit dem letzten Senden einer Anfrage an die Site ausgeführt werden sollte, aber ich hoffe auf etwas Saubereres.


1
Wenn Sie eine Hochleistungs-Site sind und RabbitMQ bereits verwenden, ist hier ein Trick, um cron
Van Gale

Wenn ich richtig verstehe, müssen Sie einige Aufgaben in Django planen. Das Beste, was ich heutzutage finde, ist dieses: celery.github.com/celery/index.html
Ali Nikneshan

Was denkst du über dies? github.com/reavis/django-cron
Domenico Monaco

Tick war allerdings nur, um Ihnen all diese Arbeit zu vermeiden. [Haftungsausschluss] Ich baue Zecke.
Siscia

2
github.com/coleifer/huey Huey muss hier erwähnt werden. Mit Django ist es lächerlich einfach einzurichten.
Brandon Bertelsen

Antworten:


363

Eine Lösung, die ich eingesetzt habe, ist folgende:

1) Erstellen Sie einen benutzerdefinierten Verwaltungsbefehl , z

python manage.py my_cool_command

2) Verwenden Sie cron(unter Linux) oderat (unter Windows), um meinen Befehl zu den erforderlichen Zeiten auszuführen.

Dies ist eine einfache Lösung, für die kein schwerer AMQP-Stack installiert werden muss. Es gibt jedoch nette Vorteile, etwas wie Sellerie zu verwenden, das in den anderen Antworten erwähnt wird. Insbesondere bei Sellerie ist es schön, dass Sie Ihre Anwendungslogik nicht in Crontab-Dateien verteilen müssen. Die Cron-Lösung eignet sich jedoch sehr gut für kleine bis mittelgroße Anwendungen, bei denen Sie nicht viele externe Abhängigkeiten benötigen.

BEARBEITEN:

In späteren atWindows- Versionen ist der Befehl für Windows 8, Server 2012 und höher veraltet. Sie können schtasks.exefür die gleiche Verwendung verwenden.

**** UPDATE **** Dies ist der neue Link von django doc zum Schreiben des benutzerdefinierten Verwaltungsbefehls


5
Ist dies eine Möglichkeit, dies ohne externe Dienste zu tun, aber mit einem nur laufenden Django-Framework-Prozess?
Sergzach

4
@Brian_Neal django_cron Anwendung.
Sergzach

2
Bitte helfen Sie mir zu verstehen, wie ich einen Verwaltungsbefehl in einer virtuellen Umgebung mit cron am letzten Tag eines jeden Monats ausführen kann.
mmrs151

2
@sergzach Ich habe diesen Kommentar weiterverfolgt und es stellte sich heraus, dass es zwei Pakete mit diesem Namen gibt. Der Django-Cron bei Google Code und der Django-Cron bei Github . Sie sind etwas unterschiedlich, aber beide interessant. Mit beiden können Sie Crones auf 'Djangonic'-Weise definieren. Der erste ist etwas älter und zielt darauf ab, ohne eine externe Aufgabe (dh den Cron) zu arbeiten. Im zweiten python manage.py runcronsFall müssen Sie einen Cron zum Ausführen festlegen, der dann alle von Ihnen definierten und registrierten Cron ausführt.
Driftcatcher

1
@sergzach Ich gehe davon aus, dass Sie sich auf den ersten beziehen, "django-cron on Google Code". Da hast du recht. Aus diesem Grund entscheide ich mich für das zweite, "django-cron on GitHub", weil Sie so ein einfaches Crontab-Setup / Management haben - nur ein Crontab, bezogen auf den Management-Befehl -, aber da Sie ein separates verwenden Cron-Prozess Sie vermeiden dieses Synchronisationsproblem (soweit ich das beurteilen kann).
Driftcatcher

152

Sellerie ist eine verteilte Aufgabenwarteschlange, die auf AMQP (RabbitMQ) basiert. Außerdem werden periodische Aufgaben cronartig behandelt (siehe periodische Aufgaben ). Abhängig von Ihrer App kann es einen Blick wert sein.

Sellerie ist mit Django ( Docs ) ziemlich einfach einzurichten , und regelmäßige Aufgaben überspringen im Falle einer Ausfallzeit tatsächlich verpasste Aufgaben. Sellerie verfügt auch über integrierte Wiederholungsmechanismen für den Fall, dass eine Aufgabe fehlschlägt.


51

Wir haben Open-Source-Anwendungen entwickelt, die meiner Meinung nach strukturiert sind. dass Brians Lösung oben auch anspielt. Wir würden uns über jedes Feedback freuen!

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

Es kommt mit einem Verwaltungsbefehl:

./manage.py runcrons

Das macht den Job. Jeder Cron wird als Klasse modelliert (also ist alles OO) und jeder Cron läuft mit einer anderen Frequenz und wir stellen sicher, dass der gleiche Cron-Typ nicht parallel läuft (falls die Cron selbst länger brauchen als ihre Frequenz!)


5
@chachra Entschuldigung, ich weiß, dass dies eine dumme Frage sein könnte, aber wird dies unter Windows funktionieren atoder wurde es speziell für die Arbeit entwickelt cron?
Bruno Finger

38

Wenn Sie ein Standard-POSIX-Betriebssystem verwenden, verwenden Sie cron .

Wenn Sie Windows verwenden, verwenden Sie at .

Schreiben Sie einen Django-Verwaltungsbefehl an

  1. Finde heraus, auf welcher Plattform sie sich befinden.

  2. Führen Sie entweder den entsprechenden "AT" -Befehl für Ihre Benutzer aus oder aktualisieren Sie die crontab für Ihre Benutzer.


10
Ich würde es gerne in meine Django-App rollen lassen, wenn es möglich ist.
TM.

@TM: Was bedeutet "in meine Django-App gerollt"? Bitte klären Sie Ihre Frage.
S.Lott

10
Ich möchte, dass die Benutzer diese App problemlos bereitstellen können, ohne selbst Cron-Jobs einrichten zu müssen.
TM.

1
Sie können die Cron-Oberfläche jederzeit in Ihre App einbinden.
Mönch

BSD, Mac und jedes Unix-ähnliche Betriebssystem haben Cron.
DylanYoung


16

Schauen Sie sich Django Poor Man's Cron an, eine Django-App, die Spambots, Suchmaschinen-Indizierungsroboter usw. verwendet, um geplante Aufgaben in ungefähr regelmäßigen Abständen auszuführen

Siehe: http://code.google.com/p/django-poormanscron/


2
Dies setzt auch voraus, dass Ihre Django-App über das Internet zugänglich ist, was bei Bereitstellungen in LANs und VPNs nicht der Fall wäre.
TimH - Codidact

10

Ich hatte vor einiger Zeit genau die gleiche Anforderung und löste sie schließlich mit APScheduler ( Benutzerhandbuch ).

Es macht das Planen von Jobs sehr einfach und hält es unabhängig von der anforderungsbasierten Ausführung von Code. Das Folgende ist ein einfaches Beispiel.

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

Hoffe das hilft jemandem!


9

Brian Neals Vorschlag, Verwaltungsbefehle über cron auszuführen, funktioniert gut, aber wenn Sie etwas Robusteres suchen (aber nicht so aufwändig wie Sellerie), würde ich in eine Bibliothek wie Kronos schauen :

# app/cron.py

import kronos

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

9

RabbitMQ und Celery bieten mehr Funktionen und Funktionen zur Aufgabenabwicklung als Cron. Wenn ein Aufgabenfehler kein Problem darstellt und Sie glauben, dass Sie beim nächsten Aufruf fehlerhafte Aufgaben bearbeiten werden, ist Cron ausreichend.

Mit Celery & AMQP können Sie die fehlerhafte Aufgabe bearbeiten und sie wird erneut von einem anderen Mitarbeiter ausgeführt (Sellerie-Mitarbeiter warten auf die nächste Aufgabe, an der gearbeitet werden soll), bis das max_retriesAttribut der Aufgabe erreicht ist. Sie können sogar Aufgaben bei einem Fehler aufrufen, z. B. das Protokollieren des Fehlers oder das Senden einer E-Mail an den Administratormax_retries erreicht wurde.

Und Sie können Sellerie- und AMQP-Server verteilen, wenn Sie Ihre Anwendung skalieren müssen.


8

Ich persönlich benutze cron, aber die Jobs Scheduling- Teile von Django-Erweiterungen sehen interessant aus.


Hängt immer noch von cron zum Auslösen ab, fügt nur eine weitere Abstraktionsschicht dazwischen hinzu. Ich bin mir nicht sicher, ob es sich persönlich lohnt.
Carl Meyer

Ich bin damit einverstanden, und nachdem ich darüber nachgedacht habe, möchte ich nicht, dass die Anforderungs-Middleware meine Site verlangsamt (ala Poormanscron oben), wenn Cron die Arbeit sowieso besser machen kann.
Van Gale

7

Obwohl Airflow nicht Teil von Django ist, handelt es sich um ein neueres Projekt (Stand 2016), das für das Aufgabenmanagement nützlich ist.

Airflow ist ein Workflow-Automatisierungs- und Planungssystem, mit dem Datenpipelines erstellt und verwaltet werden können. Eine webbasierte Benutzeroberfläche bietet dem Entwickler eine Reihe von Optionen zum Verwalten und Anzeigen dieser Pipelines.

Airflow ist in Python geschrieben und wird mit Flask erstellt.

Airflow wurde von Maxime Beauchemin bei Airbnb erstellt und im Frühjahr 2015 als Open-Source-Version bereitgestellt. Im Winter 2016 wurde es dem Inkubationsprogramm der Apache Software Foundation beigetreten. Hier finden Sie die Git-Projektseite und einige zusätzliche Hintergrundinformationen .


6

Fügen Sie Folgendes oben in Ihre cron.py-Datei ein:

#!/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

6

Ich habe gerade über diese ziemlich einfache Lösung nachgedacht:

  1. Definieren Sie eine Ansichtsfunktion do_work (req, param) wie bei jeder anderen Ansicht mit URL-Zuordnung, geben Sie eine HttpResponse zurück und so weiter.
  2. Richten Sie einen Cron-Job mit Ihren Timing-Einstellungen ein (oder verwenden Sie AT oder Scheduled Tasks in Windows), auf dem curl http: // localhost / your / mapped / url? Param = value ausgeführt wird .

Sie können Parameter hinzufügen, aber nur Parameter zur URL hinzufügen.

Sag mir, was ihr denkt.

[Update] Ich verwende jetzt den Befehl runjob von django-extensions anstelle von curl.

Mein Cron sieht ungefähr so ​​aus:

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

... und so weiter für täglich, monatlich usw. '. Sie können es auch so einrichten, dass ein bestimmter Job ausgeführt wird.

Ich finde es überschaubarer und sauberer. Es ist nicht erforderlich, einer Ansicht eine URL zuzuordnen. Definieren Sie einfach Ihre Jobklasse und Crontab und schon sind Sie fertig.


1
Das einzige Problem bei der Erkennung besteht darin, der App und der Bandbreite nicht unbedingt Last hinzuzufügen, um einen Hintergrundjob auszuführen, der besser "intern" und unabhängig von der bereitstellenden App gestartet werden sollte. Abgesehen davon ist dies ein cleverer und allgemeinerer Django-Cron, da er sogar von Agenten außerhalb des App-Servers aufgerufen werden kann!
Nemesisfixx

Sie haben Recht, deshalb habe ich Jobs von Django-Befehlserweiterungen verwendet. Siehe mein Update zu meiner Antwort.
Michael

4

Nach dem Teil des Codes kann ich alles schreiben, genau wie meine 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)
#######################################

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


3

Sie sollten auf jeden Fall django-q ausprobieren! Es erfordert keine zusätzliche Konfiguration und verfügt möglicherweise über alles, was zur Behebung von Produktionsproblemen bei kommerziellen Projekten erforderlich ist.

Es ist aktiv entwickelt und lässt sich sehr gut in Django, Django ORM, Mongo und Redis integrieren. Hier ist meine Konfiguration:

# 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,
},
}

3

Django APScheduler für Scheduler-Jobs. Advanced Python Scheduler (APScheduler) ist eine Python-Bibliothek, mit der Sie planen können, dass Ihr Python-Code später nur einmal oder regelmäßig ausgeführt wird. Sie können nach Belieben neue Jobs hinzufügen oder alte entfernen.

Hinweis: Ich bin der Autor dieser Bibliothek

Installieren Sie APScheduler

pip install apscheduler

Zeigen Sie die aufzurufende Dateifunktion an

Dateiname: scheduler_jobs.py

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

Planer konfigurieren

Erstellen Sie die Datei execute.py und fügen Sie die folgenden Codes hinzu

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

Ihre geschriebenen Funktionen Hier werden die Scheduler-Funktionen in scheduler_jobs geschrieben

import scheduler_jobs 

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

Verknüpfen Sie die Datei zur Ausführung

Fügen Sie nun die folgende Zeile am Ende der URL-Datei hinzu

import execute

2

Ich hatte heute etwas Ähnliches mit Ihrem Problem.

Ich wollte nicht, dass es vom Server verwaltet wird, obwohl Cron (und die meisten Bibliotheken waren am Ende nur Cron-Helfer).

Also habe ich ein Planungsmodul erstellt und es an den Init angehängt .

Es ist nicht der beste Ansatz, aber es hilft mir, den gesamten Code an einem einzigen Ort und mit seiner Ausführung in Bezug auf die Haupt-App zu haben.


2

Ja, die obige Methode ist so großartig. Und ich habe einige davon ausprobiert. Endlich habe ich eine Methode wie diese gefunden:

    from threading import Timer

    def sync():

        do something...

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

Genau wie rekursiv .

Ok, ich hoffe, diese Methode kann Ihre Anforderungen erfüllen. :) :)


1
Wird aufhören, wenn Ihr "Etwas" jemals ausfällt. Stellen Sie daher sicher, dass Sie alle darin enthaltenen Ausnahmen behandeln. Selbst dann könnte der Webserver Ihren Thread irgendwann beenden, nicht wahr?
Lutz Prechelt

2

Eine modernere Lösung (im Vergleich zu Sellerie) ist Django Q: https://django-q.readthedocs.io/en/latest/index.html

Es hat eine großartige Dokumentation und ist leicht zu verstehen. Die Windows-Unterstützung fehlt, da Windows das Prozessgabeln nicht unterstützt. Es funktioniert jedoch einwandfrei, wenn Sie Ihre Entwicklungsumgebung mit dem Windows für Linux-Subsystem erstellen.


Es scheint, dass Sie es immer noch in einem
Einzelcluster

1

Ich benutze Sellerie, um meine periodischen Aufgaben zu erstellen. Zuerst müssen Sie es wie folgt installieren:

pip install django-celery

Vergessen Sie nicht, sich django-celeryin Ihren Einstellungen zu registrieren , und dann können Sie Folgendes tun:

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

2
Ich stelle fest, dass dieser Rat veraltet ist und Sie Sellerie direkt integrieren können. Weitere Informationen finden Sie unter pypi.python.org/pypi/django-celery .
Peter Brittain

Sellerie-Dokumente sagen, dass dies eine Änderung in Version 3.1 war. Ich habe es selbst noch nicht versucht.
Peter Brittain

1

Ich bin mir nicht sicher, ob dies für irgendjemanden nützlich sein wird, da ich anderen Benutzern des Systems die Möglichkeit geben musste, die Jobs zu planen, ohne ihnen Zugriff auf den eigentlichen Server (Windows) Task Scheduler zu gewähren. Ich habe diese wiederverwendbare App erstellt.

Bitte beachten Sie, dass Benutzer Zugriff auf einen freigegebenen Ordner auf dem Server haben, in dem sie die erforderliche Befehls- / Task- / .bat-Datei erstellen können. Diese Aufgabe kann dann mit dieser App geplant werden.

App Name ist Django_Windows_Scheduler

Bildschirmfoto: Geben Sie hier die Bildbeschreibung ein



0

Für einfache Docker-Projekte konnte ich keine passende Antwort sehen.

Also habe ich eine Barebone-Lösung geschrieben, ohne dass externe Bibliotheken oder Trigger erforderlich sind, die von selbst ausgeführt werden. Kein externes Betriebssystem benötigt, sollte in jeder Umgebung funktionieren.

Es funktioniert durch Hinzufügen einer Middleware: 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',
    ...
]

0

Eine einfache Möglichkeit besteht darin, einen benutzerdefinierten Shell-Befehl zu schreiben (siehe Django-Dokumentation) und ihn mit einem Cronjob unter Linux auszuführen. Ich würde jedoch empfehlen, einen Nachrichtenbroker wie RabbitMQ in Verbindung mit Sellerie zu verwenden. Vielleicht können Sie sich dieses Tutorial ansehen

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.