Periodic Jobs

The @periodic decorator and its backing configuration class.

Decorator

pg_scheduler.periodic(every: timedelta | None = None, cron: str | None = None, timezone: str | ZoneInfo | None = None, use_advisory_lock: bool = False, priority: JobPriority = <JobPriority.NORMAL: normal (db_value=5)>, max_retries: int = 0, job_name: str | None = None, dedup_key: str | None = None, enabled: bool = True) Callable[source]

Decorator to mark an async function as a periodic job.

Supports two scheduling modes: 1. Interval-based: Use every parameter (e.g., every=timedelta(minutes=15)) 2. Cron-based: Use cron parameter (e.g., cron=”0 0 * * *” for daily at midnight)

Features: - Guarantees exactly one enqueue per window across many replicas (via dedup key) - Self-reschedules at the end of each run - Optional advisory-lock protection for exclusive execution - Timezone support for cron expressions

Parameters:
  • every – Time interval between executions (timedelta). Mutually exclusive with cron.

  • cron

    Cron expression string (e.g., “0 0 * * *”). Mutually exclusive with every. Format: minute hour day month day_of_week .. rubric:: Examples

    • ”0 0 * * *” = daily at midnight

    • ”0 0 * * SUN” = every Sunday at midnight

    • */15 * * * *” = every 15 minutes

    • ”0 9-17 * * MON-FRI” = every hour 9am-5pm on weekdays

  • timezone – Timezone for cron scheduling (e.g., “America/New_York”, “Europe/London”). Can be a string or ZoneInfo object. Only valid with cron. Defaults to UTC if not specified.

  • use_advisory_lock – Use PostgreSQL advisory locks for exclusive execution across replicas

  • priority – Job priority (CRITICAL, HIGH, NORMAL, LOW)

  • max_retries – Maximum retry attempts for failed executions

  • job_name – Custom job name (auto-generated from function name if None)

  • dedup_key – Custom deduplication key (auto-generated if None)

  • enabled – Whether the periodic job is enabled

Examples

# Interval-based scheduling @periodic(every=timedelta(minutes=15)) async def cleanup_temp_files():

print(“Cleaning up temp files…”)

# Cron-based scheduling (daily at midnight UTC) @periodic(cron=”0 0 * * *”) async def daily_backup():

print(“Running daily backup…”)

# Cron with timezone (every Sunday at 3am EST) @periodic(cron=”0 3 * * SUN”, timezone=”America/New_York”) async def weekly_report():

print(“Generating weekly report…”)

# Cron with priority and retries @periodic(cron=”0 9 * * MON-FRI”, timezone=”Europe/London”,

priority=JobPriority.HIGH, max_retries=3)

async def business_hours_task():

print(“Running business hours task…”)

Raises:
  • ValueError – If neither every nor cron is specified, or both are specified

  • ValueError – If timezone is specified without cron

  • ImportError – If cron is specified but croniter is not installed

  • TypeError – If decorated function is not async

PeriodicJobConfig

class pg_scheduler.periodic.PeriodicJobConfig(func: Callable, interval: timedelta | None = None, cron: str | None = None, timezone: str | ZoneInfo | None = None, use_advisory_lock: bool = False, priority: JobPriority = None, max_retries: int = 0, job_name: str | None = None, dedup_key: str | None = None, enabled: bool = True)[source]

Configuration for a periodic job.

Supports two scheduling modes: 1. Interval-based: Specify interval (timedelta) 2. Cron-based: Specify cron (cron expression string)

Parameters:
  • func – The async function to execute periodically

  • interval – Time interval between executions (mutually exclusive with cron)

  • cron – Cron expression (e.g., “0 0 * * *” for daily at midnight) (mutually exclusive with interval)

  • timezone – Timezone for cron scheduling (e.g., “America/New_York”, “Europe/London”) Uses UTC if not specified. Requires cron to be set.

  • use_advisory_lock – Use PostgreSQL advisory locks for exclusive execution

  • priority – Job priority (defaults to NORMAL)

  • max_retries – Maximum retry attempts for failed executions

  • job_name – Custom job name (auto-generated if None)

  • dedup_key – Custom deduplication key (auto-generated if None)

  • enabled – Whether the periodic job is enabled

func: Callable
interval: timedelta | None = None
cron: str | None = None
timezone: str | ZoneInfo | None = None
use_advisory_lock: bool = False
priority: JobPriority = None
max_retries: int = 0
job_name: str | None = None
dedup_key: str | None = None
enabled: bool = True
__post_init__()[source]

Set defaults and generate dedup key

__init__(func: Callable, interval: timedelta | None = None, cron: str | None = None, timezone: str | ZoneInfo | None = None, use_advisory_lock: bool = False, priority: JobPriority = None, max_retries: int = 0, job_name: str | None = None, dedup_key: str | None = None, enabled: bool = True) None