¿Configurar un trabajo programado?


519

He estado trabajando en una aplicación web con Django, y tengo curiosidad por saber si hay una manera de programar un trabajo para que se ejecute periódicamente.

Básicamente, solo quiero ejecutar la base de datos y hacer algunos cálculos / actualizaciones de forma automática y regular, pero parece que no puedo encontrar ninguna documentación sobre esto.

¿Alguien sabe cómo configurar esto?

Para aclarar: sé que puedo configurar un crontrabajo para hacer esto, pero tengo curiosidad por saber si hay alguna característica en Django que brinde esta funcionalidad. Me gustaría que las personas puedan implementar esta aplicación ellos mismos sin tener que hacer mucha configuración (preferiblemente cero).

He considerado activar estas acciones "retroactivamente" simplemente comprobando si un trabajo debería haberse ejecutado desde la última vez que se envió una solicitud al sitio, pero espero algo un poco más limpio.


1
Si eres un sitio de alto rendimiento y ya estás usando RabbitMQ, aquí hay un truco para evitar cron: Usar AMQP para hacer una programación parecida a cron
Van Gale

Si entiendo bien, debes programar algunas tareas en Django. Lo mejor que encuentro en estos días es este: celery.github.com/celery/index.html
Ali Nikneshan


Tick se ha hecho solo para evitar todo este trabajo. [Descargo de responsabilidad] Construyo tick.
Siscia

2
github.com/coleifer/huey Huey necesita una mención aquí. Es ridículamente fácil de configurar con Django.
Brandon Bertelsen

Respuestas:


363

Una solución que he empleado es hacer esto:

1) Crear un comando de gestión personalizado , por ejemplo

python manage.py my_cool_command

2) Usar cron(en Linux) oat (en Windows) para ejecutar mi comando en los momentos requeridos.

Esta es una solución simple que no requiere instalar una pila AMQP pesada. Sin embargo, hay buenas ventajas de usar algo como el apio, mencionado en las otras respuestas. En particular, con Celery es bueno no tener que distribuir la lógica de su aplicación en archivos crontab. Sin embargo, la solución cron funciona bastante bien para una aplicación de tamaño pequeño a mediano y donde no desea muchas dependencias externas.

EDITAR:

En una versión posterior de Windows, el atcomando está en desuso para Windows 8, Server 2012 y superior. Puedes usarschtasks.exe para el mismo uso.

**** ACTUALIZACIÓN **** Este es el nuevo enlace de django doc para escribir el comando de gestión personalizado


55
¿Es esta una forma de hacerlo sin servicios externos pero usando un único proceso de django framework?
sergzach

44
Aplicación @Brian_Neal django_cron.
sergzach

2
Ayúdame a comprender cómo ejecutaré un comando de administración en un entorno virtual usando cron el último día de cada mes.
mmrs151

2
@sergzach Seguí este comentario y resulta que hay dos paquetes con este nombre. El django-cron en Google Code y el django-cron en Github . Son ligeramente diferentes pero ambos interesantes. Ambos le permiten definir crons de forma 'Djangonic'. El primero es un poco más antiguo y tiene como objetivo trabajar sin una tarea externa (es decir, el cron). El segundo, por otro lado, requiere que configure un cron para python manage.py runcronsque se ejecute y luego ejecute todos los cron que haya definido y registrado.
driftcatcher

1
@sergzach Supongo que se refiere al primero, "django-cron en Google Code". Tienes razón sobre eso. Esta es la razón por la que opto por el segundo, "django-cron en GitHub", porque hace que tengas una configuración / administración de crontab simple, solo un crontab, que se refiere al comando de administración, pero ya que estás usando un comando separado proceso cron evitas este problema de sincronización (por lo que puedo decir).
driftcatcher

152

El apio es una cola de tareas distribuida, construida sobre AMQP (RabbitMQ). También maneja tareas periódicas de forma cron (ver tareas periódicas ). Dependiendo de su aplicación, puede valer la pena un vistazo.

El apio es bastante fácil de configurar con django ( docs ), y las tareas periódicas omitirán las tareas perdidas en caso de un tiempo de inactividad. El apio también tiene mecanismos de reintento integrados, en caso de que una tarea falle.


51

Hemos abierto lo que creo que es una aplicación estructurada. que la solución de Brian anterior también alude. ¡Nos encantaría cualquier / todos los comentarios!

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

Viene con un comando de gestión:

./manage.py runcrons

Eso hace el trabajo. Cada cron se modela como una clase (por lo que es todo OO) y cada cron se ejecuta a una frecuencia diferente y nos aseguramos de que el mismo tipo de cron no se ejecute en paralelo (¡en caso de que los crons tarden más tiempo en ejecutarse que su frecuencia!)


55
@chachra Lo siento, sé que esta podría ser una pregunta tonta, pero ¿esto funcionará en Windows ato fue diseñado específicamente para funcionar cron?
Bruno Finger

38

Si está utilizando un sistema operativo POSIX estándar, utiliza cron .

Si usa Windows, lo usa en .

Escriba un comando de administración de Django para

  1. Averigua en qué plataforma están.

  2. Ejecute el comando "AT" apropiado para sus usuarios o actualice el crontab para sus usuarios.


10
Me gustaría incluirlo en mi aplicación django si es posible.
TM.

@TM: ¿Qué significa "enrollado en mi aplicación django"? Por favor aclara tu pregunta.
S.Lott

10
Me gustaría que las personas puedan implementar fácilmente esta aplicación sin tener que configurar ellos mismos trabajos cron.
TM.

1
Siempre puede envolver la interfaz cron en su aplicación.
monkut

BSD, Mac y cualquier sistema operativo similar a Unix tienen cron.
DylanYoung

23

Nueva e interesante aplicación Django enchufable: django-chronograph

Solo tiene que agregar una entrada cron que actúe como temporizador, y tiene una interfaz de administrador Django muy agradable en los scripts para ejecutar.


2
django-chronograph no se mantiene. A Fork le
Menda

16

Mire Drongo Poor Man's Cron, que es una aplicación de Django que utiliza spambots, robots de indexación de motores de búsqueda y similares para ejecutar tareas programadas en intervalos aproximadamente regulares

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


2
Esto también supone que su aplicación Django es accesible desde la web, lo que no sería el caso para implementaciones en LAN y VPN.
TimH - Codidact

10

Hace un tiempo tuve exactamente el mismo requisito y terminé resolviéndolo usando APScheduler ( Guía del usuario )

Hace que los trabajos de programación sean súper simples y lo mantiene independiente de la ejecución de algún código basada en solicitudes. El siguiente es un ejemplo 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

Espero que esto ayude a alguien!


9

La sugerencia de Brian Neal de ejecutar comandos de administración a través de cron funciona bien, pero si está buscando algo un poco más robusto (pero no tan elaborado como Celery), buscaría en una biblioteca como Kronos :

# app/cron.py

import kronos

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

9

RabbitMQ y Celery tienen más características y capacidades de manejo de tareas que Cron. Si la falla de la tarea no es un problema y cree que manejará las tareas interrumpidas en la próxima llamada, entonces Cron es suficiente.

Celery & AMQP le permitirá manejar la tarea rota, y será ejecutada nuevamente por otro trabajador (los trabajadores de Celery escuchan la próxima tarea para trabajar), hasta que max_retriesse alcance el atributo de la tarea . Incluso puede invocar tareas en caso de error, como registrar el error o enviar un correo electrónico al administrador una vez quemax_retries se haya alcanzado.

Y puede distribuir servidores Celery y AMQP cuando necesite escalar su aplicación.


8

Personalmente uso cron, pero las partes de Programación de trabajos de django-extensiones parecen interesantes.


Todavía depende de cron para desencadenarse, solo agrega otra capa de abstracción en el medio. No estoy seguro de que valga la pena, personalmente.
Carl Meyer

Estoy de acuerdo, y después de pensarlo, no quiero solicitar que el middleware ralentice mi sitio (ala poormanscron arriba) cuando cron puede hacer el trabajo mejor de todos modos.
Van Gale

7

Aunque no es parte de Django, Airflow es un proyecto más reciente (a partir de 2016) que es útil para la gestión de tareas.

Airflow es un sistema de programación y automatización de flujo de trabajo que se puede utilizar para crear y administrar canalizaciones de datos. Una interfaz de usuario basada en web proporciona al desarrollador una gama de opciones para administrar y ver estas canalizaciones.

Airflow está escrito en Python y está construido usando Flask.

Airflow fue creado por Maxime Beauchemin en Airbnb y de código abierto en la primavera de 2015. Se unió al programa de incubación de Apache Software Foundation en el invierno de 2016. Aquí está la página del proyecto Git y alguna información adicional .


6

Coloque lo siguiente en la parte superior de su archivo 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

Acabo de pensar en esta solución bastante simple:

  1. Defina una función de vista do_work (req, param) como lo haría con cualquier otra vista, con mapeo de URL, devuelva un HttpResponse y así sucesivamente.
  2. Configure un trabajo cron con sus preferencias de tiempo (o utilizando AT o Tareas programadas en Windows) que ejecute curl http: // localhost / your / mapped / url? Param = value .

Puede agregar parámetros pero solo agregar parámetros a la URL.

Dime que piensan ustedes.

[Actualización] Ahora estoy usando el comando runjob de django-extensions lugar de curl.

Mi cron se parece a esto:

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

... y así sucesivamente para diario, mensual, etc. También puede configurarlo para ejecutar un trabajo específico.

Lo encuentro más manejable y más limpio. No requiere asignar una URL a una vista. Simplemente defina su clase de trabajo y crontab y estará listo.


1
El único problema que siento es que no necesariamente agrega carga a la aplicación y ancho de banda solo para ejecutar un trabajo en segundo plano que sería mejor lanzar "internamente" e independientemente de la aplicación que sirve. Pero aparte de eso, este es un django-cron inteligente y más genérico porque incluso puede ser invocado por agentes externos al servidor de la aplicación.
nemesisfixx

Tienes razón, es por eso que pasé a usar trabajos de django-command-extensions. Ver mi actualización a mi respuesta.
Michael

4

después de la parte del código, puedo escribir cualquier cosa como mi 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)
#######################################

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


3

Definitivamente deberías revisar django-q! No requiere configuración adicional y posiblemente tiene todo lo necesario para manejar cualquier problema de producción en proyectos comerciales.

Se ha desarrollado activamente y se integra muy bien con django, django ORM, mongo, redis. Aquí está mi configuración:

# 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 para trabajos de planificador. Advanced Python Scheduler (APScheduler) es una biblioteca de Python que le permite programar su código de Python para que se ejecute más tarde, ya sea solo una vez o periódicamente. Puede agregar nuevos trabajos o eliminar los antiguos sobre la marcha, según lo desee.

nota: soy el autor de esta biblioteca

Instalar APScheduler

pip install apscheduler

Ver función de archivo para llamar

nombre del archivo: Scheduler_jobs.py

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

Configurar el planificador

crea el archivo execute.py y agrega los siguientes códigos

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

Sus funciones escritas Aquí, las funciones del planificador están escritas en Scheduler_jobs

import scheduler_jobs 

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

Enlace el archivo para su ejecución

Ahora, agregue la línea a continuación en la parte inferior del archivo Url

import execute

2

Tuve algo similar con tu problema hoy.

No quería que el servidor lo manejara a través de cron (y la mayoría de las librerías solo eran ayudantes de cron al final).

Así que creé un módulo de programación y lo adjunté al init .

No es el mejor enfoque, pero me ayuda a tener todo el código en un solo lugar y con su ejecución relacionada con la aplicación principal.


2

Sí, el método anterior es muy bueno. Y probé algunos de ellos. Por fin, encontré un método como este:

    from threading import Timer

    def sync():

        do something...

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

Justo como recursivo .

Ok, espero que este método pueda cumplir con sus requisitos. :)


1
Se detendrá si su 'algo' falla, así que asegúrese de manejar todas las excepciones dentro de él. Incluso entonces, el servidor web podría matar su hilo en algún momento, ¿no es así?
Lutz Prechelt


1

Yo uso el apio para crear mis tareas periódicas. Primero debe instalarlo de la siguiente manera:

pip install django-celery

No olvide registrarse django-celeryen su configuración y luego podría hacer algo como esto:

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
Noté que este consejo está desactualizado y puede integrar el apio directamente. Ver pypi.python.org/pypi/django-celery para más detalles.
Peter Brittain

Los documentos de apio dicen que esto fue un cambio en v3.1. Todavía no lo he probado.
Peter Brittain

1

No estoy seguro de que esto sea útil para nadie, ya que tuve que proporcionar a otros usuarios del sistema para programar los trabajos, sin darles acceso al Programador de tareas del servidor (Windows) real, creé esta aplicación reutilizable.

Tenga en cuenta que los usuarios tienen acceso a una carpeta compartida en el servidor donde pueden crear el archivo de comando / tarea / .bat requerido. Esta tarea se puede programar con esta aplicación.

El nombre de la aplicación es Django_Windows_Scheduler

Captura de pantalla: ingrese la descripción de la imagen aquí



0

Para proyectos dockerizados simples, realmente no podía ver ningún ajuste de respuesta existente.

Así que escribí una solución muy básica sin la necesidad de bibliotecas externas o desencadenantes, que se ejecuta por sí sola. No se necesita un os-cron externo, debería funcionar en todos los entornos.

Funciona agregando 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

Una manera simple es escribir un comando de shell personalizado, ver la documentación de Django y ejecutarlo usando un cronjob en Linux. Sin embargo, recomendaría usar un agente de mensajes como RabbitMQ junto con apio. Tal vez puedas echar un vistazo a este tutorial

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.