Skip to content

Task

grelmicro.task

Task.

TaskError

Bases: GrelmicroError

Base grelmicro Task error.

Tasks

Tasks(
    *,
    auto_start: bool = True,
    tasks: list[Task] | None = None,
    timezone: str | None = None,
    shutdown_timeout: float | None = None,
    env_prefix: str | None = None,
    env_load: bool | None = None,
)

Bases: TaskRouter, Reconfigurable[TasksConfig]

Tasks.

Tasks class, the main entrypoint to manage scheduled tasks.

Supports live reconfiguration of shutdown_timeout via reconfigure(new_config). A swap applies to the next shutdown, not to a drain already under way. timezone is startup-only: changing the zone under a running cron task would move which wall-clock fire counts as due, and the durable last-fire state would either replay a fire or swallow one. See Live reconfiguration.

Initialize Tasks.

PARAMETER DESCRIPTION
auto_start

Automatically start all tasks.

TYPE: bool DEFAULT: True

tasks

A list of tasks to be started.

TYPE: list[Task] | None DEFAULT: None

timezone

The IANA timezone name every cron task uses.

A cron task that passes its own timezone=, and a TaskRouter that declares one, keep theirs.

Default: "UTC". When unset and env reads are enabled (see env_load and GREL_ENV_LOAD), resolves from GREL_TASK_TIMEZONE, then from the app-wide GREL_TIMEZONE, before falling back to the default.

TYPE: str | None DEFAULT: None

shutdown_timeout

Seconds to let running tasks finish their current unit of work on shutdown before they are force-cancelled. On exit a stop signal is raised so tasks unwind as soon as their in-flight work completes; this only bounds how long a task stuck mid-work delays shutdown.

Defaults to 30.0, matching Kubernetes' terminationGracePeriodSeconds. Keep it at or below the pod grace period so draining finishes before SIGKILL. Set to 0 to cancel immediately without draining.

When unset and env reads are enabled, resolves from GREL_TASK_SHUTDOWN_TIMEOUT.

TYPE: float | None DEFAULT: None

env_prefix

Override the auto-derived environment variable prefix.

Default: GREL_TASK_. Tasks takes no registration name, so two instances in one process read the same variables. Pass a prefix here to separate them.

TYPE: str | None DEFAULT: None

env_load

Whether to read environment variables.

When None (the default), follow the process-wide GREL_ENV_LOAD flag. Pass True or False to override the flag for this construction.

TYPE: bool | None DEFAULT: None

RAISES DESCRIPTION
SettingsValidationError

If a setting fails validation.

timezone property

timezone: str

The IANA timezone name cron tasks use unless they set their own.

from_config classmethod

from_config(
    config: TasksConfig,
    *,
    auto_start: bool = True,
    tasks: list[Task] | None = None,
) -> Self

Construct a Tasks from a pre-built TasksConfig.

PARAMETER DESCRIPTION
config

The pre-built tasks configuration.

Use this path when the configuration is assembled at startup from a settings tree (for example YAML, Vault, or a pydantic-settings aggregator). The environment path is bypassed and the config is used as-is.

TYPE: TasksConfig

auto_start

Automatically start all tasks.

TYPE: bool DEFAULT: True

tasks

A list of tasks to be started.

TYPE: list[Task] | None DEFAULT: None

start async

start() -> None

Start all tasks manually.

TasksConfig

Bases: BaseModel

Tasks Config.

timezone class-attribute instance-attribute

timezone: TimeZoneName = TimeZoneName(UTC_NAME)

IANA timezone every cron task uses unless it, or the TaskRouter holding it, sets its own.

shutdown_timeout class-attribute instance-attribute

shutdown_timeout: NonNegativeFloat = 30.0

Seconds to let running tasks finish their current unit of work on shutdown before they are force-cancelled.

TaskRouter

TaskRouter(
    *,
    tasks: list[Task] | None = None,
    timezone: str | None = None,
)

Task Router.

TaskRouter class, used to group task schedules, for example to structure an app in multiple files. It would then be included in the Tasks, or in another TaskRouter.

Initialize the task router.

PARAMETER DESCRIPTION
tasks

A list of tasks to be scheduled.

TYPE: list[Task] | None DEFAULT: None

timezone

The IANA timezone name every cron task in this router uses.

A cron task that passes its own timezone= keeps it. When None (the default), the router takes the timezone of the Tasks or TaskRouter that includes it, and falls back to "UTC" when nothing sets one.

TYPE: str | None DEFAULT: None

RAISES DESCRIPTION
TimezoneError

If no timezone of that name can be loaded.

tasks property

tasks: list[Task]

List of scheduled tasks.

timezone property

timezone: str | None

The timezone this router declares, or None when it declares none.

A router reports only what it was given. The timezone its tasks end up using is resolved by the owning Tasks when it starts, and a router does not read the value it would inherit.

add_task

add_task(task: Task) -> None

Add a task to the scheduler.

every

every(
    *,
    seconds: float | timedelta,
    name: str | None = None,
    lock: TaskLock | None = None,
    leader: LeaderElection | None = None,
    sync: LockPrimitive | None = None,
) -> Callable[
    [Callable[..., Any | Awaitable[Any]]],
    Callable[..., Any | Awaitable[Any]],
]

Decorate a function to run it on a fixed interval.

Supports three modes:

  • Local: No lock or leader, runs on every worker, every interval.
  • Distributed lock: Pass a lock to run at most once per interval across all workers.
  • Leader-gated: Set leader to restrict execution to the leader worker (a lock is implied).
PARAMETER DESCRIPTION
seconds

The duration between each task run.

Accepts a number of seconds or a timedelta.

Accuracy is not guaranteed and may vary with system load. Consider the execution time of the task when setting the interval.

TYPE: float | timedelta

name

The name of the task.

If None, a name will be generated automatically from the function.

TYPE: str | None DEFAULT: None

lock

Optional distributed lock for at-most-once scheduling.

Pass a TaskLock to run the task at most once per interval across all workers. Its lease_duration must be >= seconds. When the lock keeps its default "default" name, the task name is used so it does not need to be repeated. The lock's lease_duration, min_hold_duration, backend and worker are authoritative.

TYPE: TaskLock | None DEFAULT: None

leader

Optional leader election for leader gating.

When provided, the task only executes on the leader worker. Implies distributed locking (a lock is automatically configured with interval-aware defaults when no lock is given).

TYPE: LeaderElection | None DEFAULT: None

sync

Optional resource-level synchronization primitive.

Layered on top of any distributed scheduling chosen via lock or leader. Use a Lock to serialise execution against a shared resource. Whether the task runs on every worker or only one is governed by lock and leader, not this parameter.

TYPE: LockPrimitive | None DEFAULT: None

RAISES DESCRIPTION
FunctionTypeError

If the task name generation fails.

ValueError

If seconds is less than or equal to 0.

ValueError

If the lock lease_duration is less than seconds.

cron

cron(
    expr: str,
    *,
    timezone: str | None = None,
    name: str | None = None,
    misfire_grace_seconds: float | None = None,
    backend: ScheduleBackend | None = None,
    sync: LockPrimitive | None = None,
) -> Callable[
    [Callable[..., Any | Awaitable[Any]]],
    Callable[..., Any | Awaitable[Any]],
]

Decorate function to add it as a cron task.

Runs the task whenever the wall-clock time matches the cron expression in the given timezone.

Each fire is claimed against a durable last-fire state, so the task runs at most once across every worker per fire. A fire missed while every worker was down replays once on restart, bounded by misfire_grace_seconds, and only the most recent missed fire runs. Without a backend, the task runs on every worker, every fire.

The guarantee is at-most-once. A worker that claims a fire and then crashes mid-run does not retry it, because the last-fire state already advanced. Make the body idempotent, or wrap it with @retry, when correctness depends on completion.

PARAMETER DESCRIPTION
expr

The 5-field cron expression: minute hour day-of-month month day-of-week.

Each field supports *, */step, a-b, a-b/step, a comma list, and a bare integer. Day of week is 0-6 with 0 = Sunday (7 also means Sunday). When both day-of-month and day-of-week are restricted, a day matches if it matches either.

TYPE: str

timezone

The IANA timezone name used to compute fire times.

When None (the default), the task takes the timezone configured on the Tasks or TaskRouter it belongs to, and falls back to "UTC" when nothing sets one. Pass a name here to pin one task to a different timezone than the rest.

TYPE: str | None DEFAULT: None

name

The name of the task.

If None, a name will be generated automatically from the function. Also used as the schedule name for the durable last-fire state.

TYPE: str | None DEFAULT: None

misfire_grace_seconds

How late a missed fire may run when a worker comes back.

A fire missed while every worker was down replays once on restart only when now is within this many seconds of the fire. Past the budget, the fire is dropped. None (default) sets no budget, so any missed fire replays once, however late. Only the most recent missed fire ever runs, never a backlog.

TYPE: float | None DEFAULT: None

backend

The durable schedule backend.

By default, resolves through the active Grelmicro app's Coordination component. When no backend is available, the task runs on every worker, every fire.

TYPE: ScheduleBackend | None DEFAULT: None

sync

Optional resource-level synchronization primitive.

Wraps the body once this worker wins the fire. Use a Lock to serialise execution against a shared resource. Whether the task runs on every worker or only one is governed by the schedule backend, not this parameter.

TYPE: LockPrimitive | None DEFAULT: None

RAISES DESCRIPTION
FunctionTypeError

If the task name generation fails.

CronError

If the cron expression is invalid.

TimezoneError

If the timezone is not an IANA timezone name.

include_router

include_router(router: TaskRouter) -> None

Include another router in this router.

RAISES DESCRIPTION
TaskAddOperationError

If the tasks have already started.

started

started() -> bool

Check if the task manager has started.

do_mark_as_started

do_mark_as_started() -> None

Mark the task manager as started.

Do not call this method directly. It is called by the task manager when the task manager is started.