Skip to content

Observable periodic work

MIC does not replace CronJob, systemd, or a platform scheduler. The mic.scheduling module carries the application guarantees that must remain the same regardless of the trigger: distributed exclusion, checkpoints, execution state, metrics, and silence detection.

Declare and run a task

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)

The decorator attaches a specification without wrapping the function. The scheduler calls run_due(); the runner checks cadence, acquires the lock, and passes the checkpoint from the latest successful run. An exception is recorded and then propagated to the supervisor, and never advances the checkpoint.

Cooperative timeout

The timeout sets a deadline and the lock duration. The runner also detects an overrun when the function returns, but it cannot arbitrarily kill a Python thread. Batch jobs call ctx.raise_if_timed_out() at safe interruption points. Forced termination belongs to the process supervisor or Kubernetes activeDeadlineSeconds.

Tasks are synchronous. A function returning an awaitable is rejected explicitly; an application can provide a synchronous facade or run its own asynchronous worker around the MIC primitives.

Detect silence

from mic.scheduling import SilenceMonitor

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

SilenceMonitor compares the latest success with the silence_after threshold. To detect the complete disappearance of the worker, run this check in a separate supervision process. Metrics expose run count and status, duration, processed volume, latest success, and silence state.

Responsibility boundary

MIC provides Application or platform provides
Specification, cadence, and lock key CronJob, systemd, or loop trigger
In-memory or Redis store Redis availability and backup
Checkpoint after success Cursor semantics and compatibility
Cooperative timeout Forced process termination
Silence detection and metric Alert routing and on-call response