Impostare un lavoro pianificato?


519

Ho lavorato su un'app Web usando Django e sono curioso di sapere se esiste un modo per pianificare l'esecuzione periodica di un lavoro.

Fondamentalmente voglio solo scorrere il database ed eseguire alcuni calcoli / aggiornamenti su base automatica e regolare, ma non riesco a trovare alcuna documentazione su come farlo.

Qualcuno sa come impostare questo?

Per chiarire: so di poter impostare un cronlavoro per farlo, ma sono curioso di sapere se c'è qualche funzionalità in Django che fornisce questa funzionalità. Vorrei che le persone fossero in grado di distribuire questa app da soli senza dover fare molta configurazione (preferibilmente zero).

Ho pensato di innescare queste azioni "retroattivamente" semplicemente controllando se un lavoro avrebbe dovuto essere eseguito dall'ultima volta che una richiesta è stata inviata al sito, ma spero in qualcosa di un po 'più pulito.


1
Se sei un sito ad alte prestazioni e stai già utilizzando RabbitMQ, ecco un trucco per aggirare cron: Usare AMQP per programmare in modo cron
Van Gale

Se ho capito bene, devi programmare alcune attività in Django. La cosa migliore che trovo in questi giorni è questa: celery.github.com/celery/index.html
Ali Nikneshan


La zecca è stata solo per evitare tutto questo lavoro. [Disclaimer] Costruisco tick.
Siscia,

2
github.com/coleifer/huey Huey ha bisogno di una menzione qui. È ridicolmente facile da configurare con Django.
Brandon Bertelsen,

Risposte:


363

Una soluzione che ho impiegato è di fare questo:

1) Creare un comando di gestione personalizzato , ad es

python manage.py my_cool_command

2) Utilizzare cron(su Linux) oat (su Windows) per eseguire il mio comando nei tempi richiesti.

Questa è una soluzione semplice che non richiede l'installazione di uno stack AMQP pesante. Tuttavia ci sono dei bei vantaggi nell'usare qualcosa come il sedano, menzionato nelle altre risposte. In particolare, con Celery è bello non dover diffondere la logica dell'applicazione in file crontab. Tuttavia, la soluzione cron funziona abbastanza bene per un'applicazione di piccole e medie dimensioni e dove non si vogliono molte dipendenze esterne.

MODIFICARE:

Nella versione successiva di Windows il atcomando è obsoleto per Windows 8, Server 2012 e versioni successive. Puoi usare schtasks.exeper lo stesso uso.

**** AGGIORNAMENTO **** Questo è il nuovo link di django doc per la scrittura del comando di gestione personalizzato


5
È un modo per farlo senza servizi esterni ma utilizzando un solo processo di framework django in esecuzione?
sergzach,

4
Applicazione @Brian_Neal django_cron.
sergzach,

2
Aiutatemi a capire come eseguirò un comando di gestione in un ambiente virtuale usando cron l'ultimo giorno di ogni mese.
mmrs151

2
@sergzach Ho seguito questo commento e si scopre che ci sono due pacchetti con questo nome. Il django-cron su Google Code e il django-cron su Github . Sono leggermente diversi ma entrambi interessanti. Entrambi consentono di definire le croni in modo "Djangonic". Il primo è un po 'più vecchio e mira a lavorare senza un compito esterno (cioè il cron). La seconda invece richiede di impostare l'esecuzione di un cron che esegue python manage.py runcronsquindi tutti i croni che sono stati definiti e registrati.
driftcatcher,

1
@sergzach Presumo che ti riferisca al primo, "django-cron su Google Code". Hai ragione su quello. Questo è in realtà il motivo per cui ho optato per il secondo, "django-cron su GitHub", perché lo rende così hai una semplice configurazione / gestione crontab - solo un crontab, facendo riferimento al comando di gestione - ma dal momento che stai usando un separato processo cron si evita questo problema di sincronizzazione (per quanto posso dire).
driftcatcher,

152

Il sedano è una coda di attività distribuita, costruita su AMQP (RabbitMQ). Gestisce anche le attività periodiche in modo cronologico (vedere le attività periodiche ). A seconda della tua app, potrebbe valere la pena.

Il sedano è abbastanza facile da configurare con django ( docs ) e le attività periodiche salteranno effettivamente le attività perse in caso di tempi di inattività. Il sedano ha anche meccanismi di riprova integrati, nel caso in cui un'attività fallisca.


51

Abbiamo scoperto ciò che penso sia un'app strutturata. che anche la soluzione di Brian allude. Ci piacerebbe qualsiasi / tutti i feedback!

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

Viene fornito con un comando di gestione:

./manage.py runcrons

Questo fa il lavoro. Ogni cron è modellato come una classe (quindi è tutto OO) e ogni cron funziona a una frequenza diversa e ci assicuriamo che lo stesso tipo cron non funzioni in parallelo (nel caso in cui i croni stessi impieghino più tempo a correre rispetto alla loro frequenza!)


5
@chachra Siamo spiacenti, so che potrebbe essere una domanda stupida, ma funzionerà su Windows ato è stato progettato appositamente per funzionare cron?
Bruno Finger,

38

Se stai usando un sistema operativo POSIX standard, usi cron .

Se stai usando Windows, lo usi a .

Scrivi un comando di gestione Django su

  1. Scopri su quale piattaforma si trovano.

  2. Esegui il comando "AT" appropriato per i tuoi utenti o aggiorna il crontab per i tuoi utenti.


10
Mi piacerebbe averlo arrotolato nella mia app django, se possibile.
TM.

@TM: cosa significa "roll-up nella mia app django"? Per favore chiarisci la tua domanda.
S.Lott

10
Vorrei che le persone fossero in grado di distribuire facilmente questa app senza dover impostare autonomamente cron job.
TM.

1
Puoi sempre avvolgere l'interfaccia cron nella tua app.
Monaco

BSD, Mac e qualsiasi sistema operativo simile a Unix hanno cron.
DylanYoung,


16

Guarda Cronologia del povero uomo di Django che è un'app di Django che utilizza spambots, robot di indicizzazione dei motori di ricerca e simili per eseguire attività pianificate a intervalli di circa regolari

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


2
Ciò presuppone anche che la tua app Django sia accessibile dal Web, il che non sarebbe il caso delle distribuzioni su LAN e VPN.
TimH - Codidact,

10

Avevo esattamente lo stesso requisito qualche tempo fa e ho finito per risolverlo usando APScheduler ( Guida per l'utente )

Rende la pianificazione dei lavori super semplice e lo mantiene indipendente dall'esecuzione basata su richiesta di alcuni codici. Di seguito è riportato un semplice esempio.

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

Spero che questo aiuti qualcuno!


9

Il suggerimento di Brian Neal di eseguire i comandi di gestione tramite cron funziona bene, ma se stai cercando qualcosa di un po 'più robusto (ma non così elaborato come il sedano) guarderei in una libreria come Kronos :

# app/cron.py

import kronos

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

9

RabbitMQ e Sedano hanno più funzioni e capacità di gestione delle attività rispetto a Cron. Se il fallimento dell'attività non è un problema e pensi che gestirai le attività interrotte nella prossima chiamata, allora Cron è sufficiente.

Sedano e AMQP ti permetteranno di gestire l'attività interrotta e verrà eseguita di nuovo da un altro lavoratore (i lavoratori del sedano ascoltano l'attività successiva su cui lavorare), fino a quando non max_retriesviene raggiunto l' attributo dell'attività. È anche possibile richiamare attività in caso di errore, come la registrazione dell'errore o l'invio di un'e-mail all'amministratore una voltamax_retries è stato raggiunto.

E puoi distribuire i server Celery e AMQP quando devi ridimensionare la tua applicazione.


8

Personalmente uso cron, ma le parti di Job Scheduling di django-extensions sembrano interessanti.


Dipende ancora da cron per l'attivazione, aggiunge solo un altro livello di astrazione nel mezzo. Non sono sicuro che ne valga la pena, personalmente.
Carl Meyer,

Sono d'accordo, e dopo averci pensato, non voglio che il middleware delle richieste rallenti il ​​mio sito (ala poormanscron sopra) quando cron può comunque fare meglio il lavoro.
Van Gale,

7

Sebbene non faccia parte di Django, Airflow è un progetto più recente (a partire dal 2016) che è utile per la gestione delle attività.

Airflow è un sistema di automazione e pianificazione del flusso di lavoro che può essere utilizzato per creare e gestire pipeline di dati. Un'interfaccia utente basata sul Web offre allo sviluppatore una gamma di opzioni per la gestione e la visualizzazione di queste pipeline.

Airflow è scritto in Python ed è costruito usando Flask.

Airflow è stato creato da Maxime Beauchemin presso Airbnb e open source nella primavera del 2015. È entrato a far parte del programma di incubazione della Apache Software Foundation nell'inverno del 2016. Ecco la pagina del progetto Git e alcune informazioni di base aggiuntive .


6

Inserisci quanto segue nella parte superiore del file 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

Ho appena pensato a questa soluzione piuttosto semplice:

  1. Definisci una funzione di visualizzazione do_work (req, param) come faresti con qualsiasi altra vista, con mappatura URL, restituisce un HttpResponse e così via.
  2. Imposta un processo cron con le tue preferenze di temporizzazione (o usando AT o Attività pianificate in Windows) che esegue l' arricciatura http: // localhost / your / mapped / url? Param = value .

Puoi aggiungere parametri ma semplicemente aggiungere parametri all'URL.

Dimmi cosa ne pensate voi ragazzi.

[Aggiornamento] Ora sto usando il comando runjob da django-extensions anziché curl.

Il mio cron ha un aspetto simile al seguente:

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

... e così via ogni giorno, mensilmente, ecc. È inoltre possibile configurarlo per eseguire un lavoro specifico.

Lo trovo più gestibile e più pulito. Non richiede il mapping di un URL a una vista. Basta definire la propria classe professionale e crontab e il gioco è fatto.


1
l'unico problema che intendo è aggiungere necessariamente carico all'app e alla larghezza di banda solo per eseguire un lavoro in background che sarebbe meglio essere lanciato "internamente" e indipendentemente dall'app di servizio. Ma a parte questo, questo è un django-cron intelligente e più generico perché può anche essere invocato da agenti esterni al server dell'app!
nemesisfixx,

Hai ragione, ecco perché sono passato a usare i lavori da django-command-extensions. Vedi il mio aggiornamento alla mia risposta.
Michael,

4

dopo la parte del codice, posso scrivere qualcosa come il mio 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)
#######################################

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


3

Dovresti assolutamente dare un'occhiata a Django-q! Non richiede alcuna configurazione aggiuntiva e ha probabilmente tutto il necessario per gestire eventuali problemi di produzione su progetti commerciali.

È attivamente sviluppato e si integra molto bene con django, django ORM, mongo, redis. Ecco la mia configurazione:

# 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 per lavori Scheduler. Advanced Python Scheduler (APScheduler) è una libreria Python che consente di pianificare l'esecuzione del codice Python in un secondo momento, una sola volta o periodicamente. Puoi aggiungere nuovi lavori o rimuovere quelli vecchi al volo come preferisci.

nota: sono l'autore di questa biblioteca

Installa APScheduler

pip install apscheduler

Visualizza la funzione del file da chiamare

nome del file: scheduler_jobs.py

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

Configurazione dello scheduler

crea il file execute.py e aggiungi i seguenti codici

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

Le tue funzioni scritte Qui, le funzioni dello scheduler sono scritte in scheduler_jobs

import scheduler_jobs 

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

Collegare il file per l'esecuzione

Ora, aggiungi la riga in basso nella parte inferiore del file Url

import execute

2

Ho avuto qualcosa di simile con il tuo problema oggi.

Non volevo che fosse gestito dal server tramite cron (e la maggior parte delle librerie erano solo aiutanti di cron alla fine).

Quindi ho creato un modulo di programmazione e l'ho collegato all'init .

Non è l'approccio migliore, ma mi aiuta ad avere tutto il codice in un unico posto e con la sua esecuzione correlata all'app principale.


2

Sì, il metodo sopra è fantastico. E ho provato alcuni di loro. Alla fine, ho trovato un metodo come questo:

    from threading import Timer

    def sync():

        do something...

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

Proprio come ricorsivo .

Ok, spero che questo metodo possa soddisfare le tue esigenze. :)


1
Si fermerà se il tuo "qualcosa" non riesce mai, quindi assicurati di gestire tutte le eccezioni al suo interno. Anche allora, il web server potrebbe uccidere il tuo thread ad un certo punto, no?
Lutz Prechelt


1

Uso il sedano per creare i miei compiti periodici. Innanzitutto è necessario installarlo come segue:

pip install django-celery

Non dimenticare di registrarti django-celerynelle tue impostazioni e quindi potresti fare qualcosa del genere:

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
Ho notato che questo consiglio non è aggiornato e puoi integrare direttamente il sedano. Vedi pypi.python.org/pypi/django-celery per i dettagli.
Peter Brittain,

I documenti del sedano affermano che questo è stato un cambiamento nella v3.1. Non l'ho ancora provato da solo.
Peter Brittain,

1

Non sono sicuro che questo sarà utile a chiunque, dato che ho dovuto fornire ad altri utenti del sistema la pianificazione dei lavori, senza dare loro l'accesso all'utilità di pianificazione del server (Windows), ho creato questa app riutilizzabile.

Si noti che gli utenti hanno accesso a una cartella condivisa sul server in cui possono creare il file comando / task / .bat richiesto. Questa attività può quindi essere pianificata utilizzando questa app.

Il nome dell'app è Django_Windows_Scheduler

Immagine dello schermo: inserisci qui la descrizione dell'immagine



0

Per i semplici progetti dockerizzati, non riuscivo a vedere alcuna risposta adatta.

Quindi ho scritto una soluzione molto barebone senza la necessità di librerie o trigger esterni, che funziona da solo. Nessun os-cron esterno necessario, dovrebbe funzionare in ogni ambiente.

Funziona aggiungendo 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 modo semplice è scrivere un comando shell personalizzato, consultare la documentazione Django ed eseguirlo usando un cronjob su Linux. Tuttavia consiglio vivamente di utilizzare un broker di messaggi come RabbitMQ accoppiato con sedano. Forse puoi dare un'occhiata a questo tutorial

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.