sched en Python: programa eventos

Publicado el: 28/08/2026
Tempo de leitura: 5 minutos
Person writing appointments on a calendar with a blue pen. High angle view.

El módulo sched implementa un scheduler simple de eventos en memoria. Mantiene una cola ordenada por instante y prioridad, espera hasta el momento adecuado y ejecuta callbacks. Es útil en scripts, simulaciones, tests, pequeños servicios y aplicaciones que necesitan temporización local sin una dependencia externa.

sched no es cron, una cola distribuida ni infraestructura durable. Los eventos desaparecen cuando termina el proceso, los callbacks largos retrasan los siguientes y el módulo no ofrece retries, persistencia ni ejecución en varias máquinas. Úsalo para scheduling local y controlado.

Crea un scheduler

El constructor recibe una función de tiempo y una función de espera. Los defaults modernos usan time.monotonic y time.sleep.

import sched
import time

scheduler = sched.scheduler(time.monotonic, time.sleep)

Un reloj monotónico es apropiado para intervalos porque no retrocede cuando cambia el reloj civil.

Programa con retraso relativo

enter() agenda una acción después de un delay.

def ejecutar(nombre):
    print("ejecutando", nombre)

scheduler.enter(5, 1, ejecutar, argument=("tarea",))
scheduler.run()

El segundo argumento es la prioridad. Los números menores se ejecutan primero cuando los eventos comparten instante.

Argumentos y kwargs

Usa argument para parámetros posicionales y kwargs para los nombrados.

scheduler.enter(
    2,
    1,
    enviar,
    argument=(destino,),
    kwargs={"intento": 1},
)

Los argumentos explícitos son más fáciles de probar y registrar que closures con estado mutable.

Programa en un instante absoluto

enterabs() recibe un valor compatible con la función de tiempo.

cuando = time.monotonic() + 10
scheduler.enterabs(cuando, 1, ejecutar, argument=("absoluta",))

No mezcles timestamps de time.time() con un scheduler basado en time.monotonic().

Prioridades

Cuando varios eventos tienen el mismo instante, la prioridad define el orden.

scheduler.enter(1, 10, ejecutar, argument=("normal",))
scheduler.enter(1, 1, ejecutar, argument=("urgente",))

La prioridad no interrumpe un callback que ya está ejecutándose.

Objeto Event

enter() y enterabs() devuelven un evento que puede cancelarse.

evento = scheduler.enter(30, 1, ejecutar)

Guarda la referencia junto al identificador lógico de la tarea.

Cancela un evento

cancel() elimina un evento pendiente.

try:
    scheduler.cancel(evento)
except ValueError:
    print("el evento ya no está pendiente")

El cancelamiento falla si ya se ejecutó, fue eliminado o no pertenece a esa cola.

Inspecciona la cola

La propiedad queue muestra eventos pendientes en orden.

for evento in scheduler.queue:
    print(evento.time, evento.priority, evento.action)

Úsala para observabilidad, no para modificar directamente la estructura.

Ejecuta sin bloquear hasta el próximo evento

run(blocking=False) procesa eventos vencidos y devuelve información sobre el siguiente plazo.

proximo = scheduler.run(blocking=False)

Este modo ayuda a integrar el scheduler con una GUI o loop principal.

Callbacks largos

El scheduler ejecuta callbacks de forma secuencial. Una acción de diez segundos retrasa todos los eventos que venzan durante ese tiempo.

Mantén callbacks cortos o envía trabajo a un executor limitado. No crees una thread ilimitada por evento.

Eventos atrasados

Cuando el proceso está ocupado, sched no descarta automáticamente eventos vencidos. Los ejecuta tan pronto como puede.

La aplicación debe decidir si la tarea todavía tiene sentido. Compara el instante planificado con el real y define tolerancia.

Tareas recurrentes

Un callback puede agendar su próxima ejecución.

INTERVALO = 60


def recurrente(proximo_instante):
    ejecutar_trabajo()
    siguiente = proximo_instante + INTERVALO
    scheduler.enterabs(siguiente, 1, recurrente, argument=(siguiente,))

primero = time.monotonic() + INTERVALO
scheduler.enterabs(primero, 1, recurrente, argument=(primero,))

Calcular desde el instante planificado reduce drift.

Evita drift

Si el callback usa enter(INTERVALO, ...) después de terminar, la duración de la tarea se suma a cada ciclo.

Usa plazos absolutos para cadencia fija y delays relativos solo cuando la regla sea esperar después de concluir.

Fallos en callbacks

Una excepción sale de run(). El scheduler mantiene su estructura, pero los eventos posteriores esperan hasta que el caller vuelva a ejecutar run().

def seguro():
    try:
        ejecutar_trabajo()
    except Exception:
        logger.exception("evento falló")

Captura errores solo cuando exista una política clara.

Retries

sched no repite automáticamente.

Reintenta únicamente fallos transitorios, con límite, backoff, jitter e idempotencia. No repitas errores de validación.

Threads

Las implementaciones modernas permiten insertar eventos desde varias threads, pero el lifecycle y los callbacks todavía requieren diseño.

No mantengas locks de aplicación mientras ejecutas callbacks que puedan necesitar los mismos recursos.

Eventos anteriores insertados por otra thread

Si una thread espera un evento lejano y otra inserta uno más cercano, la integración externa debe hacer que el loop reevalúe la cola.

Para sistemas complejos, puede ser mejor asyncio o un scheduler dedicado.

Integra ThreadPoolExecutor

El scheduler puede enviar trabajo a un pool limitado.

from concurrent.futures import ThreadPoolExecutor

executor = ThreadPoolExecutor(max_workers=4)
scheduler.enter(1, 1, executor.submit, argument=(ejecutar_trabajo,))

Observa futures y cierra el executor durante shutdown. Consulta concurrent.futures en Python.

Shutdown

Mantén una flag o evento de parada. Deja de crear recurrencias, cancela pendientes cuando corresponda y espera trabajo enviado.

Un scheduler en memoria no conserva tareas tras el cierre.

Horario civil

Para reglas como “09:00 local”, usa una solución que gestione timezone, horario de verano y persistencia.

time.monotonic() mide intervalos; no representa una fecha de calendario.

Tests determinísticos

Inyecta funciones falsas de tiempo y delay.

class Reloj:
    def __init__(self):
        self.ahora = 0
    def time(self):
        return self.ahora
    def sleep(self, retraso):
        self.ahora += retraso

reloj = Reloj()
test_scheduler = sched.scheduler(reloj.time, reloj.sleep)

Los tests avanzan sin sleeps reales.

Persistencia

Si los eventos deben sobrevivir a restarts, guarda la intención en base o cola durable y reconstruye al iniciar.

No serialices callbacks arbitrarios. Persiste un tipo aprobado y parámetros validados.

Seguridad

No permitas que usuarios agenden callables Python arbitrarios. Mapea comandos permitidos a funciones conocidas.

Aplica límites de cantidad, frecuencia, prioridad y tamaño.

Observabilidad

Registra ID lógico, instante planificado, inicio real, retraso, duración, resultado e intento.

Métricas de cola, lateness y fallos muestran callbacks bloqueantes.

Cuándo usar otra herramienta

Usa cron o Task Scheduler para procesos independientes, asyncio para apps asíncronas, colas durables para trabajo persistente y bibliotecas especializadas para calendarios complejos.

sched encaja en una cola temporal local y pequeña.

Errores comunes

Los fallos frecuentes son mezclar relojes, ejecutar callbacks largos, introducir drift, asumir persistencia, ignorar excepciones, olvidar cancelación, tratar prioridad como preemption y usar sleeps reales en tests.

Conclusión

sched ofrece scheduling local mediante una cola temporal. Usa reloj monotónico para intervalos, deadlines absolutos para cadencia fija, prioridades para desempate y callbacks cortos.

Añade cancelación, observabilidad y una política explícita de errores. Consulta la documentación oficial de sched y concurrent.futures en Python.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Detailed close-up texture of a snake's patterned skin showcasing natural patterns and scales.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    contextvars en Python: contexto async

    Aprende contextvars en Python para contexto por task, request IDs, logging, copy_context, propagación a threads y restauración con tokens.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    bisect en Python: listas ordenadas

    Aprende bisect en Python para búsqueda binaria, inserción ordenada, duplicados, funciones key, rangos, rankings y concurrencia segura.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    Crop unrecognizable person in gray sweater applying glue stick on paper while forming photo album on floor
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    heapq en Python: colas de prioridad

    Aprende heapq en Python para colas de prioridad, top-k, merge, empates estables, actualización de prioridades, lazy deletion y backpressure.

    Ler mais

    Tempo de leitura: 4 minutos
    28/08/2026
    Close-up of hands using a compact black calculator on a white marble surface, displaying numbers.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    array en Python: números compactos

    Aprende array en Python para almacenar números compactos, usar typecodes, bytes, archivos, memoryview y layouts binarios portables.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    Close-up of a man with binary code projected on his face, symbolizing cybersecurity.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    struct en Python: datos binarios

    Aprende struct en Python para empacar datos binarios, controlar endianness, offsets, padding, buffers, sockets y validación segura.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    A young girl exploring a library's card catalog, symbolizes research and curiosity.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    mmap en Python: archivos en memoria

    Aprende mmap en Python para mapear archivos, buscar bytes, editar regiones, compartir memoria, alinear offsets y sincronizar accesos.

    Ler mais

    Tempo de leitura: 6 minutos
    28/08/2026