Scheduling con Schedule y Cron
La automatización de procesos no sería completa sin la capacidad de ejecutar tareas en momentos específicos sin intervención manual. En esta lección exploraremos dos herramientas fundamentales para programar tareas: la biblioteca Schedule para Python y el sistema Cron de Unix/Linux.
¿Qué es el Scheduling?
El scheduling o programación de tareas es la técnica que permite ejecutar código de forma automática en intervalos determinados o en momentos específicos. Imagina que necesitas enviar reportes diarios por correo, limpiar archivos temporales cada semana, o monitorear un servidor cada 15 minutos. Sin scheduling, tendrías que ejecutar manualmente cada tarea, lo cual es insostenible y propenso a errores.
Python ofrece la biblioteca schedule, una solución elegante y sencilla para programaciones dentro del propio script. Para sistemas operativos Unix-like, cron proporciona scheduling a nivel del sistema operativo, permitiendo ejecutar cualquier comando o script en horarios definidos.
La Biblioteca Schedule de Python
La biblioteca schedule es perfecta para tareas dentro de aplicaciones Python. Su API es intuitiva y permite encadenar métodos de forma fluida.
Instalación
La instalación es trivial mediante pip:
pip install schedule
Ejemplo Básico
import schedule
import time
def tarea_ejemplo():
print("Ejecutando tarea programada...")
# Programar una tarea cada día a las 9:00
schedule.every().day.at("09:00").do(tarea_ejemplo)
# Programar cada 15 minutos
schedule.every(15).minutes.do(tarea_ejemplo)
# Programar cada hora
schedule.every().hour.do(tarea_ejemplo)
# Bucle infinito que ejecuta las tareas pendientes
while True:
schedule.run_pending()
time.sleep(1)
Métodos de Programación Disponibles
La biblioteca ofrece múltiples opciones de frecuencia:
- schedule.every(segundos).seconds.do(funcion) - Ejecuta cada N segundos
- schedule.every().minute.do(funcion) - Ejecuta cada minuto
- schedule.every().hour.do(funcion) - Ejecuta cada hora
- schedule.every().day.at("HH:MM").do(funcion) - Ejecuta a hora específica
- schedule.every().monday.do(funcion) - Ejecuta cada lunes
- schedule.every().week.do(funcion) - Ejecuta semanalmente
Ejemplo Práctico: Generador de Reportes
import schedule
import time
from datetime import datetime
def generar_reporte_diario():
"""Genera un reporte de ventas del día"""
fecha = datetime.now().strftime("%Y-%m-%d")
print(f"Generando reporte del {fecha}...")
# Aquí iría la lógica de generación del reporte
def enviar_notificacion():
"""Envía una notificación de estado"""
print("Enviando notificación de estado...")
# Lógica de envío de notificación
# Programar múltiples tareas
schedule.every().day.at("08:00").do(generar_reporte_diario)
schedule.every(30).minutes.do(enviar_notificacion)
print("Sistema de reportes iniciado...")
while True:
schedule.run_pending()
time.sleep(1)
Cron: Scheduling a Nivel de Sistema Operativo
Cron es el daemon de programación de tareas en sistemas Unix/Linux. A diferencia de schedule, cron funciona fuera de Python, permitiendo ejecutar scripts, comandos o programas en horarios específicos definidos en archivos crontab.
Sintaxis de Cron
Cada línea en un crontab sigue esta estructura:
* * * * * comando
│ │ │ │ │
│ │ │ │ └─── Día de la semana (0-7, donde 0 y 7 son domingo)
│ │ │ └────── Mes (1-12)
│ │ └──────── Día del mes (1-31)
│ └────────── Hora (0-23)
└──────────── Minuto (0-59)
Caracteres Especiales
- asterisco (*) - Cualquier valor
- guión (-) - Rango de valores (1-5)
- coma (,) - Lista de valores (1,3,5)
- barra (/) - Paso/intervalo (*/15)
Ejemplos Prácticos de Cron
# Ejecutar cada minuto
* * * * * /usr/bin/python3 /home/usuario/script.py
# Ejecutar cada 15 minutos
*/15 * * * * /usr/bin/python3 /home/usuario/script.py
# Ejecutar a las 6:00 AM cada día
0 6 * * * /usr/bin/python3 /home/usuario/backup.py
# Ejecutar cada lunes a las 8:00 AM
0 8 * * 1 /usr/bin/python3 /home/usuario/reporte.py
# Ejecutar el primer día de cada mes a medianoche
0 0 1 * * /usr/bin/python3 /home/usuario/cierre_mensual.py
# Ejecutar cada hora durante horario laboral (8AM-6PM)
0 8-18 * * 1-5 /usr/bin/python3 /home/usuario/tarea_laboral.py
Gestión de Crontabs
# Ver el crontab actual
crontab -l
# Editar el crontab
crontab -e
# Eliminar todo el crontab
crontab -r
# Ver logs de cron (en sistemas Ubuntu/Debian)
sudo grep CRON /var/log/syslog
Comparación: Schedule vs Cron
Schedule es ideal para tareas dentro de aplicaciones Python que necesitan ejecutarse mientras la aplicación está en ejecución. Cron es mejor para tareas del sistema operativo, scripts independientes, o cuando necesitas que las tareas persistan incluso si la aplicación Python se cierra.
- Schedule: Código Python puro, fácil de integrar, se ejecuta mientras el script corre, ideal para bots, servicios largos
- Cron: A nivel de SO, persiste entre ejecuciones, mejor para scripts standalone, tareas de mantenimiento del sistema
Ejemplo Avanzado: Combinando Schedule con Logging
import schedule
import time
import logging
from datetime import datetime
# Configurar logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('tareas_programadas.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
def tarea_con_manejo_errores():
"""Tarea con manejo robusto de errores"""
try:
logger.info("Iniciando tarea programada")
# Simular trabajo que podría fallar
resultado = proceso_complejo()
logger.info(f"Tarea completada: {resultado}")
return resultado
except Exception as e:
logger.error(f"Error en tarea programada: {e}")
raise
def proceso_complejo():
# Tu lógica de negocio aquí
return "Éxito"
# Limpiarjobsprevious schedule.every().day.at("09:00").do(tarea_con_manejo_errores)
schedule.every().friday.at("17:00").do(tarea_con_manejo_errores)
logger.info("Sistema de scheduling iniciado")
while True:
schedule.run_pending()
time.sleep(60)
Errores Comunes
1. No incluir un bucle de ejecución
Uno de los errores más frecuentes es definir tareas programadas pero olvidar el bucle que las ejecuta:
# ❌ INCORRECTO - Las tareas nunca se ejecutan
schedule.every().day.at("09:00").do(mi_tarea)
# El script termina aquí y las tareas nunca se ejecutan
# ✅ CORRECTO
schedule.every().day.at("09:00").do(mi_tarea)
while True:
schedule.run_pending()
time.sleep(1)
2. Confundir la sintaxis de Cron
Es común olvidar que en cron los campos van en orden específico. Un error típico:
# ❌ INCORRECTO - Executará cada minuto de cada hora del día 9
9 * * * * comando # Esto ejecuta a los minutos 9, no a las 9:00
# ✅ CORRECTO - Executa a las 9:00 AM cada día
0 9 * * * comando # Minuto 0, hora 9
3. No manejar excepciones en tareas programadas
Si una tarea falla y no se maneja la excepción, puede detener todo el proceso de scheduling:
# ❌ INCORRECTO - Una excepción puede detener todo
def tarea_peligrosa():
datos = carga_externa() # Si falla, todo se detiene
procesa(datos)
# ✅ CORRECTO - Manejo robusto de errores
def tarea_segura():
try:
datos = carga_externa()
procesa(datos)
except Exception as e:
print(f"Error en tarea: {e}")
# Loguear pero no detener otras tareas
schedule.every().hour.do(tarea_segura)
Checklist de Dominio
- Comprendo la diferencia entre scheduling a nivel de aplicación vs. sistema operativo
- Sé instalar y utilizar la biblioteca
scheduleen Python - Puedo programar tareas con diferentes frecuencias (minutos, horas, días, semanas)
- Entiendo la sintaxis de 5 campos de cron y sus caracteres especiales
- Sé crear, editar y eliminar entradas en crontab
- Implemento manejo de errores en tareas programadas
- Elijo correctamente entre Schedule y Cron según el caso de uso
- Configuro logging para monitorear tareas programadas
- Identifico y soluciono los errores comunes de scheduling
- Aplico las mejores prácticas de scheduling en proyectos reales