Je travaille sur une application Web utilisant Django et je suis curieux de savoir s'il existe un moyen de planifier l'exécution périodique d'un travail.
En gros, je veux juste parcourir la base de données et faire des calculs/mises à jour de façon automatique et régulière, mais je ne trouve pas de documentation à ce sujet.
Est-ce que quelqu'un sait comment mettre cela en place?
Pour clarifier: je sais que je peux configurer un travail cron
pour le 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 config (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 demande envoyée sur le site, mais j'espère un résultat un peu plus propre.
Une solution que j'ai employée est de faire ceci:
1) Créez une commande de gestion custom , 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.
C'est une solution simple qui ne nécessite pas l'installation d'une pile AMQP lourde. Cependant, il y a de beaux 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 à répartir la logique de votre application dans des fichiers crontab. Cependant, la solution cron fonctionne assez bien pour une application de taille petite à moyenne et pour laquelle vous ne voulez pas beaucoup de dépendances externes.
MODIFIER:
Dans les versions ultérieures de Windows, la commande at
est obsolète pour Windows 8, Server 2012 et versions ultérieures. Vous pouvez utiliser schtasks.exe
pour le même usage.
Celery est une file d’attente distribuée, construite sur AMQP (RabbitMQ). Il gère également les tâches périodiques de manière cronienne (voir tâches périodiques ). En fonction de votre application, cela pourrait valoir le coup d'oeil.
Le céleri est assez facile à configurer avec Django ( docs ), et des tâches périodiques ignoreront les tâches manquées en cas d’indisponibilité. Le céleri a également des mécanismes de nouvelle tentative intégrés, au cas où une tâche échouerait.
Nous avons open-source ce que je pense est une application structurée. la solution de Brian ci-dessus y fait également allusion. J'aimerais tout/tous les commentaires!
https://github.com/tivix/Django-cron
Il vient avec une commande de gestion:
./manage.py runcrons
Cela fait le travail. Chaque cron est modélisé en tant que classe (donc tout est sur OO) et chaque cron fonctionne à 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 prennent plus de temps que leur fréquence!)
Merci!
Si vous utilisez un système d’exploitation POSIX standard, vous utilisez cron .
Si vous utilisez Windows, vous utilisez at .
Ecrivez une commande de gestion Django à
Déterminez sur quelle plate-forme ils sont.
Exécutez la commande "AT" appropriée pour vos utilisateurs, ou mettez à jour la crontab pour vos utilisateurs.
Nouvelle application Django connectable intéressante: Django-chronograph
Vous devez seulement ajouter une entrée cron qui agit comme une minuterie, et vous avez une très belle interface admin Django dans les scripts à exécuter.
Regardez Django Poor Man's Cron, une application Django qui utilise des robots spammeurs, des robots d'indexation des moteurs de recherche et autres pour exécuter des tâches planifiées à intervalles réguliers
RabbitMQ et Celery ont plus de fonctionnalités et de capacités de gestion de tâches que Cron. Si l’échec de la tâche n’est pas un problème et que vous pensez gérer des tâches interrompues lors du prochain appel, Cron suffit.
Celery & AMQP vous permettra de gérer la tâche interrompue et sera exécutée à nouveau par un autre ouvrier (les ouvriers de Celery écoutent la tâche suivante sur laquelle travailler) jusqu'à ce que l'attribut max_retries
de la tâche soit atteint. Vous pouvez même appeler des tâches en cas d'échec, comme consigner l'échec ou envoyer un courrier électronique à l'administrateur une fois que le max_retries
a été atteint.
Et vous pouvez distribuer des serveurs Celery et AMQP lorsque vous avez besoin de faire évoluer votre application.
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 du type Kronos :
# app/cron.py
import kronos
@kronos.register('0 * * * *')
def task():
pass
Personnellement, j’utilise cron, mais le emploi du temps parties de Django-extensions semble intéressant.
Placez les éléments suivants 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
J'avais exactement les mêmes exigences il y a quelque temps et j'ai fini par les résoudre en utilisant APScheduler ( Guide de l'utilisateur )
Il simplifie les tâches de planification et les maintient indépendantes de l'exécution de certains codes à partir de requêtes. Voici un exemple simple que j'ai utilisé dans mon code.
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!
Je viens de penser à cette solution plutôt simple:
Vous pouvez ajouter des paramètres mais en ajoutant simplement des paramètres à l'URL.
Dites-moi ce que vous en pensez.
[Update] J'utilise maintenant la commande runjob de Django-extensions au lieu de curl.
Mon cron ressemble à quelque chose comme ça:
@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 sur une vue. Définissez simplement votre classe d'emploi et votre crontab et vous êtes prêt.
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 flux de travail qui peut être utilisé pour créer et gérer des pipelines de données. Une interface Web fournit au développeur une gamme d’options pour la gestion et la visualisation de ces pipelines.
Airflow est écrit en Python et est construit en utilisant Flask.
Airflow a été créé par Maxime Beauchemin chez Airbnb et en source ouverte 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 ajouts informations générales .
après la partie de code, je peux écrire n'importe quoi comme mon view.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)
#######################################
de http://www.cotellese.net/2007/09/27/running-external-scripts-against-Django-models/
Vous devez absolument consulter Django-q! Il ne nécessite aucune configuration supplémentaire et dispose probablement de tout le nécessaire pour gérer les problèmes de production des 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,
},
}
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 étaient juste des aides cron à la fin).
J'ai donc créé un module de planification et l'a connecté au init.
Ce n'est pas la meilleure approche, mais cela m'aide à avoir tout le code en un seul endroit et à son exécution liée à l'application principale.
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. :)
J'utilise le céleri pour créer mes tâches périodiques. Tout d'abord, vous devez l'installer comme suit:
pip install Django-celery
N'oubliez pas d'enregistrer Django-celery
dans vos paramètres pour pouvoir 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
Je ne suis pas sûr que cela sera utile à quiconque, car je devais fournir aux autres utilisateurs du système la planification des 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 programmée à l'aide de cette application.
Le nom de l'application est Django_Windows_Scheduler
Django Q est une solution plus moderne (par rapport au céleri): https://Django-q.readthedocs.io/en/latest/index.html
Il possède une excellente documentation et est facile à maîtriser. La prise en charge de Windows fait défaut, car Windows ne prend pas en charge la mise en fourrière de processus. Mais cela fonctionne bien si vous créez votre environnement de développement à l'aide du sous-système Windows pour Linux.
Si vous voulez quelque chose de plus fiable que Céleri _, essayez TaskHawk qui repose sur AWS SQS/SNS.
Le moyen le plus simple est d'écrire une commande shell personnalisée, voir Documentation Django et de l'exécuter à l'aide d'un cronjob sur linux. Cependant, je recommanderais fortement d'utiliser un courtier de messages comme RabbitMQ associé au céleri. Peut-être pourriez-vous jeter un coup d’œil sur This Tutorial
Pour les projets simples dockerisés, je ne pouvais pas vraiment voir aucune réponse adaptée.
J'ai donc écrit une solution très dépourvue de bases, sans recourir à des bibliothèques externes ni à des déclencheurs, qui fonctionne toute seule. Aucun os-cron externe n'est nécessaire, il 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',
...
]