28. Scheduling con Cron
Programa scripts para ejecución automática periódica
Has creado reportes automáticos y sistemas de envío de emails, pero todavía requieren que ejecutes el script manualmente. En esta lección aprenderás a programar ejecuciones automáticas para que todo funcione sin intervención humana.
El problema de la ejecución manual
Incluso con scripts automatizados, si debes ejecutarlos manualmente:
- Puedes olvidar ejecutarlos
- No funcionan fuera de horario laboral o fines de semana
- Requieren que estés disponible a horas específicas
- No escalan (10 reportes = 10 ejecuciones manuales)
Solución: Scheduling automático que ejecuta scripts en horarios predefinidos.
Opciones de scheduling por sistema operativo
Linux/Mac: Cron
Cron es el scheduler nativo de Unix/Linux. Extremadamente confiable y usado en producción por millones de empresas.
Ventajas:
- Integrado en el sistema operativo
- Cero dependencias adicionales
- Muy confiable
- Logs nativos del sistema
Windows: Task Scheduler
Task Scheduler es el equivalente de Windows a cron.
Ventajas:
- GUI intuitiva
- Integración con Windows
- Triggers avanzados
Python: Librería schedule
Librería Python multiplataforma para scheduling simple.
Ventajas:
- Sintaxis Python simple
- Multiplataforma
- No requiere permisos de administrador
Cron: Fundamentos
Sintaxis de crontab
Cron usa 5 campos para definir cuándo ejecutar:
* * * * * comando_a_ejecutar
│ │ │ │ │
│ │ │ │ └─── Día de la semana (0-7, 0 y 7 = Domingo)
│ │ │ └───── Mes (1-12)
│ │ └─────── Día del mes (1-31)
│ └───────── Hora (0-23)
└─────────── Minuto (0-59)
Ejemplos comunes
# Cada día a las 8:00 AM
0 8 * * * /usr/bin/python3 /ruta/al/script.py
# Cada hora
0 * * * * /usr/bin/python3 /ruta/al/script.py
# Cada 15 minutos
*/15 * * * * /usr/bin/python3 /ruta/al/script.py
# Lunes a viernes a las 9 AM
0 9 * * 1-5 /usr/bin/python3 /ruta/al/script.py
# Primer día del mes a las 7 AM
0 7 1 * * /usr/bin/python3 /ruta/al/script_mensual.py
# Cada domingo a medianoche
0 0 * * 0 /usr/bin/python3 /ruta/al/script_semanal.py
Implementación práctica
Paso 1: Preparar script para producción
# daily_report.py
"""
Script de reporte diario - Optimizado para cron
"""
import sys
import os
from datetime import datetime
import logging
# Configurar logging para cron
logging.basicConfig(
filename='/var/log/analytics/daily_report.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def main():
"""Función principal"""
try:
logging.info("="*60)
logging.info("INICIO - Reporte Diario")
logging.info("="*60)
# Importar después de configurar logging
from report_generator import ReportGenerator
from email_sender import EmailSender
# Generar reportes
logging.info("Generando reportes...")
generator = ReportGenerator(data_path='/home/analytics/data/ventas.csv')
pdf_file = generator.generar_reporte_pdf()
excel_file = generator.generar_reporte_excel()
html_file = generator.generar_reporte_html()
metricas = generator.calcular_metricas()
logging.info(f"Reportes generados: PDF, Excel, HTML")
# Enviar emails
logging.info("Enviando emails...")
sender = EmailSender()
sender.enviar_reporte_completo(
grupo_destinatarios='todos',
pdf_path=pdf_file,
excel_path=excel_file,
html_path=html_file,
metricas=metricas
)
sender.cerrar_conexion()
logging.info("="*60)
logging.info("FIN - Proceso completado exitosamente")
logging.info("="*60)
return 0
except Exception as e:
logging.error(f"ERROR CRÍTICO: {e}", exc_info=True)
return 1
if __name__ == "__main__":
sys.exit(main())
Paso 2: Configurar cron en Linux/Mac
# 1. Abrir editor de crontab
# crontab -e
# 2. Agregar trabajos programados
# Reporte diario a las 8 AM
0 8 * * * /usr/bin/python3 /home/analytics/daily_report.py >> /var/log/analytics/cron.log 2>&1
# Reporte semanal cada lunes a las 9 AM
0 9 * * 1 /usr/bin/python3 /home/analytics/weekly_report.py >> /var/log/analytics/cron.log 2>&1
# Reporte mensual el primer día del mes a las 7 AM
0 7 1 * * /usr/bin/python3 /home/analytics/monthly_report.py >> /var/log/analytics/cron.log 2>&1
# Scraping de competidores cada 6 horas
0 */6 * * * /usr/bin/python3 /home/analytics/competitor_scraper.py >> /var/log/analytics/cron.log 2>&1
# Backup diario de datos a las 2 AM
0 2 * * * /usr/bin/python3 /home/analytics/backup_data.py >> /var/log/analytics/cron.log 2>&1
Paso 3: Verificar configuración
# Ver crontab actual
# crontab -l
# Ver logs de cron (Ubuntu/Debian)
# tail -f /var/log/syslog | grep CRON
# Ver logs de cron (CentOS/RHEL)
# tail -f /var/log/cron
# Verificar si cron está corriendo
# systemctl status cron
Windows: Task Scheduler
Crear tarea programada con GUI
- Abrir "Task Scheduler" (Programador de tareas)
- Click "Create Basic Task" (Crear tarea básica)
- Nombre: "Daily Analytics Report"
- Trigger: "Daily" a las 8:00 AM
- Action: "Start a program"
- Program:
C:\Python39\python.exe - Arguments:
C:\analytics\daily_report.py - Finish
Crear tarea con PowerShell
# PowerShell script para crear tarea
$Action = New-ScheduledTaskAction -Execute "C:\Python39\python.exe" -Argument "C:\analytics\daily_report.py"
$Trigger = New-ScheduledTaskTrigger -Daily -At 8am
Register-ScheduledTask -TaskName "Daily Analytics Report" -Action $Action -Trigger $Trigger -Description "Generates and sends daily analytics report"
Python: Librería schedule
Para desarrollo y testing, schedule es excelente:
# scheduler.py
"""
Scheduler Python multiplataforma
"""
import schedule
import time
from datetime import datetime
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def reporte_diario():
"""Ejecuta reporte diario"""
logging.info("Ejecutando reporte diario...")
# Tu código aquí
from daily_report import main
main()
def reporte_semanal():
"""Ejecuta reporte semanal"""
logging.info("Ejecutando reporte semanal...")
# Tu código aquí
def scraping_competidores():
"""Scrapea precios de competidores"""
logging.info("Scrapeando competidores...")
# Tu código aquí
# Programar tareas
schedule.every().day.at("08:00").do(reporte_diario)
schedule.every().monday.at("09:00").do(reporte_semanal)
schedule.every(6).hours.do(scraping_competidores)
# Loop principal
print("Scheduler iniciado. Presiona Ctrl+C para detener.")
print("\nTareas programadas:")
for job in schedule.jobs:
print(f" - {job}")
try:
while True:
schedule.run_pending()
time.sleep(60) # Verificar cada minuto
except KeyboardInterrupt:
print("\nScheduler detenido.")
Mejores prácticas
1. Usar rutas absolutas
# ❌ MAL - Rutas relativas
df = pd.read_csv('data/ventas.csv')
# ✅ BIEN - Rutas absolutas
df = pd.read_csv('/home/analytics/data/ventas.csv')
# ✅ MEJOR - Rutas configurables
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
df = pd.read_csv(os.path.join(BASE_DIR, 'data', 'ventas.csv'))
2. Redireccionar logs
# Capturar stdout y stderr
0 8 * * * /usr/bin/python3 /ruta/al/script.py >> /var/log/analytics/output.log 2>&1
# Explicación:
# >> /var/log/analytics/output.log → Append stdout al archivo
# 2>&1 → Redirigir stderr a stdout
3. Configurar variables de entorno
# En crontab, configurar PATH y variables necesarias
PATH=/usr/local/bin:/usr/bin:/bin
PYTHONPATH=/home/analytics/lib
EMAIL_PASSWORD=tu_app_password
0 8 * * * /usr/bin/python3 /home/analytics/daily_report.py
4. Notificaciones de errores
# script_wrapper.py
"""
Wrapper que envía email si el script falla
"""
import subprocess
import sys
from email_sender import EmailSender
def run_script_with_notifications(script_path):
"""Ejecuta script y notifica errores"""
try:
result = subprocess.run(
['/usr/bin/python3', script_path],
capture_output=True,
text=True,
timeout=600 # 10 minutos máximo
)
if result.returncode != 0:
# Script falló, enviar alerta
sender = EmailSender()
sender.enviar_email(
destinatarios=['admin@tuempresa.com'],
asunto=f"ERROR: Script {script_path} falló",
cuerpo_html=f"""
<h2>Error en script automatizado</h2>
<p><strong>Script:</strong> {script_path}</p>
<p><strong>Código de salida:</strong> {result.returncode}</p>
<h3>Output:</h3>
<pre>{result.stdout}</pre>
<h3>Errores:</h3>
<pre>{result.stderr}</pre>
"""
)
return 1
return 0
except subprocess.TimeoutExpired:
# Script tomó demasiado tiempo
sender = EmailSender()
sender.enviar_email(
destinatarios=['admin@tuempresa.com'],
asunto=f"TIMEOUT: Script {script_path}",
cuerpo_html=f"<p>El script excedió el tiempo máximo de ejecución.</p>"
)
return 1
if __name__ == "__main__":
sys.exit(run_script_with_notifications(sys.argv[1]))
Monitoreo y debugging
Ver historial de ejecuciones
# En Linux, ver últimas ejecuciones de cron
grep CRON /var/log/syslog | tail -20
# Ver solo tu usuario
grep "$(whoami)" /var/log/syslog | grep CRON | tail -10
Testing antes de programar
# 1. Ejecutar script manualmente primero
python3 /home/analytics/daily_report.py
# 2. Verificar que genera output correcto
# 3. Revisar logs
cat /var/log/analytics/daily_report.log
# 4. Solo después programar en cron
Debugging de problemas comunes
Problema 1: Script no ejecuta
# Verificar permisos de ejecución
ls -l /home/analytics/daily_report.py
# Dar permisos si es necesario
chmod +x /home/analytics/daily_report.py
Problema 2: Python no encontrado
# Usar ruta absoluta de Python
which python3 # Copiar output
# Usar ese path en crontab
0 8 * * * /usr/bin/python3 /home/analytics/daily_report.py
Problema 3: Variables de entorno faltantes
# Cron tiene PATH limitado, especificar todo
PATH=/usr/local/bin:/usr/bin:/bin
PYTHONPATH=/home/analytics
HOME=/home/analytics
0 8 * * * cd /home/analytics && /usr/bin/python3 daily_report.py
Casos de uso reales
1. E-commerce: Reportes múltiples
# Reporte de ventas diario (8 AM)
0 8 * * * /usr/bin/python3 /home/analytics/sales_report.py
# Análisis de inventario (cada 4 horas)
0 */4 * * * /usr/bin/python3 /home/analytics/inventory_check.py
# Reporte de marketing semanal (lunes 9 AM)
0 9 * * 1 /usr/bin/python3 /home/analytics/marketing_weekly.py
# Dashboard mensual (día 1 a las 7 AM)
0 7 1 * * /usr/bin/python3 /home/analytics/monthly_dashboard.py
2. Startup SaaS: Métricas en tiempo real
# Métricas de usuario cada 15 minutos
*/15 * * * * /usr/bin/python3 /home/analytics/user_metrics.py
# Reporte diario de MRR (7 AM)
0 7 * * * /usr/bin/python3 /home/analytics/mrr_report.py
# Análisis de churn semanal (domingo medianoche)
0 0 * * 0 /usr/bin/python3 /home/analytics/churn_analysis.py
3. Agencia de marketing: Clientes múltiples
# Reportes de clientes (cada hora durante horario laboral)
0 9-18 * * * /usr/bin/python3 /home/analytics/client_reports.py
# Scraping de métricas de competencia (cada 12 horas)
0 */12 * * * /usr/bin/python3 /home/analytics/competitor_metrics.py
Resumen de la lección
✅ Configuraste cron en Linux/Mac para ejecución automática ✅ Aprendiste Task Scheduler en Windows para scheduling ✅ Implementaste librería schedule de Python multiplataforma ✅ Aplicaste mejores prácticas de rutas absolutas, logs y monitoreo ✅ Creaste notificaciones automáticas de errores
🎯 Próxima lección: 29. Mejores Prácticas y Siguientes Pasos - Testing, deployment y cómo avanzar
En la última lección consolidarás todo lo aprendido con testing, logging profesional, versionado con Git y los siguientes pasos en tu carrera como analista de datos. ¡Estás a una lección de completar el curso!
¿Completaste esta lección?
Marca esta lección como completada. Tu progreso se guardará en tu navegador.