Configurer un travail planifié?


519

J'ai travaillé sur une application Web utilisant Django, et je suis curieux de savoir s'il existe un moyen de planifier un travail à exécuter périodiquement.

Fondamentalement, je veux simplement parcourir la base de données et faire des calculs / mises à jour sur une base automatique et régulière, mais je n'arrive pas à trouver de documentation sur cela.

Est-ce que quelqu'un sait comment configurer cela?

Pour clarifier: je sais que je peux configurer un crontravail pour ce faire, mais je suis curieux de savoir s'il existe une fonctionnalité dans Django qui fournit cette fonctionnalité. J'aimerais que les gens puissent déployer cette application eux-mêmes sans avoir à faire beaucoup de configuration (de préférence zéro).

J'ai envisagé de déclencher ces actions "rétroactivement" en vérifiant simplement si un travail aurait dû être exécuté depuis la dernière fois qu'une demande a été envoyée sur le site, mais j'espère quelque chose d'un peu plus propre.


1
Si vous êtes un site à hautes performances et que vous utilisez déjà RabbitMQ, voici une astuce pour contourner cron: utiliser AMQP pour effectuer une planification semblable à cron
Van Gale

Si je comprends bien, vous devez planifier certaines tâches dans Django. La meilleure chose que je trouve ces jours-ci est celle-ci: celery.github.com/celery/index.html
Ali Nikneshan


Tick ​​a été pensé pour vous éviter tout ce travail. [Avertissement] Je construis tick.
Siscia

2
github.com/coleifer/huey Huey a besoin d'une mention ici. C'est ridiculement facile à installer avec Django.
Brandon Bertelsen

Réponses:


363

Une solution que j'ai employée est de faire ceci:

1) Créez une commande de gestion personnalisée , par exemple

python manage.py my_cool_command

2) Utilisez cron(sous Linux) ou at(sous Windows) pour exécuter ma commande aux moments requis.

Il s'agit d'une solution simple qui ne nécessite pas l'installation d'une pile AMQP lourde. Cependant, il y a de bons avantages à utiliser quelque chose comme le céleri, mentionné dans les autres réponses. En particulier, avec Celery, il est agréable de ne pas avoir à étendre la logique de votre application dans des fichiers crontab. Cependant, la solution cron fonctionne très bien pour une application de petite à moyenne taille et où vous ne voulez pas beaucoup de dépendances externes.

ÉDITER:

Dans la version ultérieure de Windows, la atcommande est déconseillée pour Windows 8, Server 2012 et supérieur. Vous pouvez utiliser schtasks.exepour le même usage.

**** MISE À JOUR **** Ceci est le nouveau lien de django doc pour écrire la commande de gestion personnalisée


5
Est-ce un moyen de le faire sans services externes mais en utilisant un processus de framework django uniquement en cours d'exécution?
sergzach

4
Application @Brian_Neal django_cron.
sergzach

2
Veuillez m'aider à comprendre comment exécuter une commande de gestion dans un environnement virtuel à l'aide de cron le dernier jour de chaque mois.
mmrs151

2
@sergzach J'ai suivi ce commentaire et il s'avère qu'il y a deux paquets avec ce nom. Le django-cron sur Google Code et le django-cron sur Github . Ils sont légèrement différents mais tous deux intéressants. Les deux vous permettent de définir des crons de manière «djangonique». Le premier est un peu plus ancien et vise à travailler sans tâche externe (ie le cron). Le second, d'autre part, vous oblige à définir un cron à exécuter python manage.py runcronsqui exécute ensuite tous les crons que vous avez définis et enregistrés.
driftcatcher

1
@sergzach Je suppose que vous faites référence au premier, "django-cron sur Google Code". Vous avez raison à ce sujet. C'est en fait pourquoi j'opte pour le second, "django-cron sur GitHub", car il permet d'avoir une configuration / gestion crontab simple - un seul crontab, se référant à la commande de gestion - mais puisque vous utilisez un autre processus cron vous évitez ce problème de synchronisation (pour autant que je sache).
driftcatcher

152

Le céleri est une file d'attente de tâches distribuées, basée sur AMQP (RabbitMQ). Il gère également les tâches périodiques de façon cron (voir tâches périodiques ). Selon votre application, cela peut valoir le coup d'œil.

Le céleri est assez facile à configurer avec django ( docs ), et les tâches périodiques ignoreront en fait les tâches manquées en cas d'arrêt. Le céleri dispose également de mécanismes de relance intégrés, en cas d'échec d'une tâche.


51

Nous avons ouvert ce que je pense être une application structurée. que la solution de Brian y fait également allusion. Nous aimerions tout / tous les commentaires!

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

Il est livré avec une commande de gestion:

./manage.py runcrons

Cela fait l'affaire. Chaque cron est modélisé comme une classe (donc tout est OO) et chaque cron s'exécute à une fréquence différente et nous nous assurons que le même type de cron ne fonctionne pas en parallèle (au cas où les crons eux-mêmes prennent plus de temps à exécuter que leur fréquence!)


5
@chachra Désolé, je sais que cela pourrait être une question stupide, mais cela fonctionnera-t-il sur Windows atou a-t-il été spécialement conçu pour fonctionner avec cron?
Bruno Finger

38

Si vous utilisez un système d'exploitation POSIX standard, vous utilisez cron .

Si vous utilisez Windows, vous utilisez à .

Ecrivez une commande de gestion Django dans

  1. Découvrez sur quelle plateforme ils se trouvent.

  2. Exécutez la commande "AT" appropriée pour vos utilisateurs ou mettez à jour la crontab pour vos utilisateurs.


10
J'aimerais le faire rouler dans mon application django si possible.
TM.

@TM: Que signifie "enroulé dans mon application django"? Veuillez clarifier votre question.
S.Lott

10
J'aimerais que les gens puissent déployer facilement cette application sans avoir à configurer eux-mêmes les tâches cron.
TM.

1
Vous pouvez toujours envelopper l'interface cron dans votre application.
monkut

BSD, Mac et tout système d'exploitation de type Unix ont cron.
DylanYoung du


16

Regardez Django Poor Man's Cron qui est une application Django qui utilise des spambots, des robots d'indexation des moteurs de recherche et autres pour exécuter des tâches planifiées à intervalles approximativement réguliers

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


2
Cela suppose également que votre application Django est accessible à partir du Web, ce qui ne serait pas le cas pour les déploiements sur les LAN et les VPN.
TimH - Codidact

10

J'avais exactement la même exigence il y a quelque temps, et j'ai fini par la résoudre en utilisant APScheduler ( Guide de l'utilisateur )

Il rend la planification des tâches super simple et la garde indépendante de l'exécution basée sur les requêtes de certains codes. Voici un exemple simple.

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

J'espère que cela aide quelqu'un!


9

La suggestion de Brian Neal d'exécuter des commandes de gestion via cron fonctionne bien, mais si vous cherchez quelque chose d'un peu plus robuste (mais pas aussi élaboré que Celery), je chercherais dans une bibliothèque comme Kronos :

# app/cron.py

import kronos

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

9

RabbitMQ et Celery ont plus de fonctionnalités et de capacités de gestion des tâches que Cron. Si l'échec de la tâche n'est pas un problème et que vous pensez que vous gérerez les tâches rompues lors du prochain appel, alors Cron est suffisant.

Celery & AMQP vous permettra de gérer la tâche cassée, et elle sera exécutée à nouveau par un autre travailleur (les travailleurs de Celery écoutent la prochaine tâche à travailler), jusqu'à ce que l' max_retriesattribut de la tâche soit atteint. Vous pouvez même invoquer des tâches en cas d'échec, comme la consignation de l'échec ou l'envoi d'un e-mail à l'administrateur une fois le message max_retriesatteint.

Et vous pouvez distribuer des serveurs Celery et AMQP lorsque vous avez besoin de faire évoluer votre application.


8

Personnellement , j'utilise Cron, mais les ordonnancement des travaux parties de django-extensions semble intéressant.


Dépend toujours de cron pour le déclenchement, ajoute juste une autre couche d'abstraction entre les deux. Je ne sais pas si ça vaut le coup, personnellement.
Carl Meyer

Je suis d'accord, et après y avoir pensé, je ne veux pas que le middleware demande de ralentir mon site (ala poormanscron ci-dessus) quand cron peut faire le travail mieux de toute façon.
Van Gale

7

Bien que ne faisant pas partie de Django, Airflow est un projet plus récent (à partir de 2016) qui est utile pour la gestion des tâches.

Airflow est un système d'automatisation et de planification de workflow qui peut être utilisé pour créer et gérer des pipelines de données. Une interface utilisateur Web offre au développeur une gamme d'options pour gérer et afficher ces pipelines.

Airflow est écrit en Python et est construit à l'aide de Flask.

Airflow a été créé par Maxime Beauchemin chez Airbnb et open source au printemps 2015. Il a rejoint le programme d'incubation de la Apache Software Foundation à l'hiver 2016. Voici la page du projet Git et quelques informations complémentaires .


6

Placez ce qui suit en haut de votre fichier 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

6

Je viens de penser à cette solution assez simple:

  1. Définissez une fonction de vue do_work (req, param) comme vous le feriez avec n'importe quelle autre vue, avec le mappage d'URL, retournez une HttpResponse et ainsi de suite.
  2. Configurez un travail cron avec vos préférences de synchronisation (ou en utilisant AT ou des tâches planifiées dans Windows) qui exécute curl http: // localhost / votre / mappé / url? Param = valeur .

Vous pouvez ajouter des paramètres mais simplement ajouter des paramètres à l'URL.

Dites-moi ce que vous en pensez.

[Mise à jour] J'utilise maintenant la commande runjob de django-extensions au lieu de curl.

Mon cron ressemble à ceci:

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

... et ainsi de suite pour tous les jours, tous les mois, etc '. Vous pouvez également le configurer pour exécuter un travail spécifique.

Je le trouve plus facile à gérer et plus propre. Ne nécessite pas de mapper une URL à une vue. Définissez simplement votre classe d'emploi et crontab et vous êtes prêt.


1
le seul problème que je ressens est d'ajouter nécessairement de la charge à l'application et de la bande passante juste pour exécuter un travail en arrière-plan qui serait mieux lancé "en interne" et indépendant de l'application qui sert. Mais à part ça, c'est un django-cron intelligent et plus générique car il peut même être invoqué par des agents externes au serveur de l'application!
nemesisfixx

Vous avez raison, c'est pourquoi je suis passé à l'utilisation de travaux à partir de django-command-extensions. Voir ma mise à jour de ma réponse.
Michael

4

après la partie de code, je peux écrire n'importe quoi comme mon 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)
#######################################

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


3

Vous devriez certainement vérifier django-q! Il ne nécessite aucune configuration supplémentaire et possède très probablement tout le nécessaire pour gérer les problèmes de production sur les projets commerciaux.

Il est activement développé et s'intègre très bien avec django, django ORM, mongo, redis. Voici ma configuration:

# 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 for Scheduler Jobs. Advanced Python Scheduler (APScheduler) est une bibliothèque Python qui vous permet de planifier votre code Python pour qu'il soit exécuté plus tard, soit une seule fois, soit périodiquement. Vous pouvez ajouter de nouveaux emplois ou supprimer les anciens à la volée à votre guise.

note: je suis l'auteur de cette bibliothèque

Installer APScheduler

pip install apscheduler

Afficher la fonction de fichier à appeler

nom de fichier: scheduler_jobs.py

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

Configuration du planificateur

créer le fichier execute.py et ajouter les codes ci-dessous

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

Vos fonctions écrites Ici, les fonctions du planificateur sont écrites dans scheduler_jobs

import scheduler_jobs 

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

Lier le fichier pour exécution

Maintenant, ajoutez la ligne ci-dessous au bas du fichier URL

import execute

2

J'ai eu quelque chose de similaire avec votre problème aujourd'hui.

Je ne voulais pas le faire gérer par le serveur via cron (et la plupart des bibliothèques n'étaient que des aides cron à la fin).

J'ai donc créé un module de planification et je l'ai attaché à l' init .

Ce n'est pas la meilleure approche, mais cela m'aide à avoir tout le code en un seul endroit et avec son exécution liée à l'application principale.


2

Oui, la méthode ci-dessus est tellement géniale. Et j'ai essayé certains d'entre eux. Enfin, j'ai trouvé une méthode comme celle-ci:

    from threading import Timer

    def sync():

        do something...

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

Tout comme récursif .

Ok, j'espère que cette méthode peut répondre à vos besoins. :)


1
S'arrêtera si votre «quelque chose» échoue, alors assurez-vous de gérer toutes les exceptions qu'il contient. Même alors, le serveur Web pourrait tuer votre thread à un moment donné, n'est-ce pas?
Lutz Prechelt

2

Une solution plus moderne (par rapport au céleri) est Django Q: https://django-q.readthedocs.io/en/latest/index.html

Il a une excellente documentation et est facile à gérer. La prise en charge de Windows fait défaut, car Windows ne prend pas en charge le forking de processus. Mais cela fonctionne très bien si vous créez votre environnement de développement à l'aide du sous-système Windows pour Linux.


Il semble que vous pouvez toujours l'utiliser en mode cluster unique sur Windows
Yushin Washio

1

J'utilise le céleri pour créer mes tâches périodiques. Vous devez d'abord l'installer comme suit:

pip install django-celery

N'oubliez pas de vous enregistrer django-celerydans vos paramètres et vous pourriez alors faire quelque chose comme ceci:

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
Je remarque que ce conseil est obsolète et que vous pouvez directement intégrer le céleri. Voir pypi.python.org/pypi/django-celery pour plus de détails.
Peter Brittain

Les documents sur le céleri disent qu'il s'agissait d'un changement dans la version 3.1. Je ne l'ai pas encore essayé moi-même.
Peter Brittain

1

Je ne suis pas sûr que cela sera utile à quiconque, car je devais fournir à d'autres utilisateurs du système pour planifier les travaux, sans leur donner accès au planificateur de tâches du serveur (Windows), j'ai créé cette application réutilisable.

Veuillez noter que les utilisateurs ont accès à un dossier partagé sur le serveur où ils peuvent créer le fichier de commande / tâche / .bat requis. Cette tâche peut ensuite être planifiée à l'aide de cette application.

Le nom de l'application est Django_Windows_Scheduler

Capture d'écran: entrez la description de l'image ici



0

Pour les projets dockers simples, je ne voyais pas vraiment de réponse existante.

J'ai donc écrit une solution très dépouillée sans avoir besoin de bibliothèques ou de déclencheurs externes, qui fonctionne seule. Aucun os-cron externe nécessaire, devrait fonctionner dans tous les environnements.

Cela fonctionne en ajoutant un 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

Un moyen simple est d'écrire une commande shell personnalisée voir la documentation Django et de l'exécuter en utilisant un cronjob sur linux. Cependant, je recommanderais fortement d'utiliser un courtier de messages comme RabbitMQ couplé à du céleri. Vous pouvez peut-être jeter un œil à ce tutoriel

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.