Aller au contenu

Travail périodique observable

MIC ne remplace pas CronJob, systemd ou un ordonnanceur de plateforme. Le module mic.scheduling porte les garanties applicatives qui doivent rester identiques quel que soit le déclencheur : exclusion distribuée, point de reprise, état d'exécution, métriques et détection du silence.

Déclarer et exécuter une tâche

from mic.locking import RedisDistributedLock
from mic.scheduling import (
    PeriodicTaskRunner,
    RedisSchedulingStore,
    TaskContext,
    TaskResult,
    periodic,
)


@periodic(
    name="collect:k8s",
    every="15m",
    lock="collect:k8s",
    timeout="10m",
    silence_after="35m",
)
def collect(ctx: TaskContext) -> TaskResult:
    processed, next_cursor = collect_batch(ctx.checkpoint)
    ctx.raise_if_timed_out()
    return TaskResult(processed=processed, checkpoint=next_cursor)


store = RedisSchedulingStore(redis_url="redis://redis:6379/0")
runner = PeriodicTaskRunner(
    lock_backend=RedisDistributedLock(redis_url="redis://redis:6379/0"),
    store=store,
    metrics=metrics,
)
runner.run_due(collect)

Le décorateur attache une spécification sans envelopper la fonction. Le planificateur appelle run_due() ; le moteur vérifie la cadence, acquiert le verrou et transmet le point de reprise du dernier succès. Une exception est tracée puis propagée au superviseur et ne fait jamais avancer ce point.

Timeout coopératif

Le timeout définit une échéance et la durée du verrou. Le runner détecte aussi un dépassement au retour, mais il ne peut pas tuer arbitrairement un thread Python. Les traitements par lots appellent ctx.raise_if_timed_out() à des points d'arrêt sûrs. Un arrêt forcé appartient au superviseur de processus ou à activeDeadlineSeconds sur Kubernetes.

Les tâches sont synchrones. Une fonction qui retourne un awaitable est refusée explicitement ; l'application peut fournir une façade synchrone ou exécuter son propre worker asynchrone autour des primitives MIC.

Détecter le silence

from mic.scheduling import SilenceMonitor

alerts = SilenceMonitor(store=store, metrics=metrics).check([collect])

SilenceMonitor compare le dernier succès au seuil silence_after. Pour détecter la disparition totale du worker, ce contrôle doit tourner dans un processus de supervision distinct. Les métriques exposent le nombre et le statut des exécutions, leur durée, le volume traité, le dernier succès et l'état de silence.

Frontière de responsabilité

MIC fournit L'application ou la plateforme fournit
Spécification, cadence et clé de verrou Déclencheur CronJob, systemd ou boucle
Store mémoire ou Redis Disponibilité et sauvegarde de Redis
Point de reprise après succès Sémantique et compatibilité du curseur
Timeout coopératif Arrêt forcé du processus
Détection et métrique de silence Routage de l'alerte et astreinte