Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.2.3 - 2026-03-30¶
Added¶
Configurable polling backoff: New
PollingConfigdataclass for fine-grained control over job listener polling behaviormin_interval– sleep between polls when jobs are being claimed (default: 0.05s)max_interval– upper bound for backoff when idle (default: 2.0s)backoff_multiplier– exponential backoff factor when no jobs are found (default: 1.5)idle_start_interval– initial idle interval before backoff kicks in (default: 0.5s)semaphore_full_interval– sleep when all concurrency slots are occupied (default: 1.0s)jitter– toggle random jitter to prevent thundering herd (default: True)
New
polling_configparameter onScheduler.__init__(uses sensible defaults when omitted)
Changed¶
Job listener now uses exponential backoff instead of fixed sleep intervals
Polls quickly after claiming jobs, backs off gradually when idle, resets on activity
Configurable via
PollingConfig(previously hardcoded to 0.05s busy / 2.0s idle)
Semaphore-full sleep is now configurable via
PollingConfig.semaphore_full_interval(previously hardcoded to 1.0s)Error recovery sleep in listener now uses
max_intervalinstead of a hardcoded 5s
Migration Notes¶
Backward Compatible: Default
PollingConfigvalues match the previous hardcoded behaviorNo Breaking Changes:
polling_configis optional; existing code works without modification
0.2.2 - 2026-03-16¶
Changed¶
Updated and streamlined README / PyPI page
0.2.1 - 2026-03-15¶
Fixed¶
Per-job misfire_grace_time ignored when scheduler default is None: The job expiration logic was entirely skipped when the scheduler’s
misfire_grace_timewas set toNone, causing jobs with explicit per-jobmisfire_grace_timeto never expire. Removed the Python-side guard so the SQL query now always runs and relies onmisfire_grace_time IS NOT NULLto correctly expire only jobs with an explicit grace time.get_periodic_job_status crashes for cron-based periodic jobs: Calling
get_periodic_job_statuson a cron-based job raisedAttributeErrorbecause it unconditionally accessedconfig.interval.total_seconds(). Now correctly handles both interval-based and cron-based jobs, returningintervalorcron/timezonefields as appropriate.
0.2.0 - 2026-02-02¶
Added¶
Bulk job scheduling: New
schedule_bulk()method for high-performance batch insertsSchedule thousands of jobs in a single database transaction
10-100x faster than individual
schedule()calls for batch operationsNew
JobSpecdataclass for defining job specificationsSupports all existing job parameters (priority, retries, custom IDs, misfire grace time)
Configurable
batch_sizeparameter for chunking large batches (default: 1000)Conflict resolution support (IGNORE, REPLACE, RAISE) applied to entire batch
Configurable batch claiming: New
batch_claim_limitparameter inScheduler.__init__to control max jobs claimed per batch (default: 10)Cron-based scheduling: Full support for cron expressions in
@periodicdecoratorUse
cronparameter instead ofevery(e.g.,cron="0 0 * * *"for daily at midnight)Supports all standard cron syntax:
*/15 * * * *,0 9-17 * * MON-FRI, etc.Requires
croniter>=3.0.0dependency
Timezone support: Schedule cron jobs in any timezone
Use
timezoneparameter with cron expressions (e.g.,timezone="America/New_York")Supports both string timezone names and
ZoneInfoobjectsAutomatically converts to UTC for internal storage
Enhanced
@periodicdecorator: Now supports both interval and cron-based scheduling modesInterval-based:
@periodic(every=timedelta(minutes=15))Cron-based:
@periodic(cron="0 0 * * *")Cron with timezone:
@periodic(cron="0 3 * * SUN", timezone="America/New_York")
New priority levels: Added
JobPriority.HIGHandJobPriority.LOWfor finer-grained priority controlCRITICAL(1) - Highest priorityHIGH(3) - High priorityNORMAL(5) - Default priorityLOW(8) - Low priority
Per-job misfire grace time configuration: Jobs can now override the scheduler’s default grace time via the
misfire_grace_timeparameter inschedule()Support for
misfire_grace_time=Noneto disable job expiration entirelySentinel pattern (
_UNSET) to distinguish between “parameter not specified” and “explicitly set to None”Database migration support for
misfire_grace_timecolumn (automatically applied to existing databases)
Changed¶
Code organization improvements: Major refactoring for better modularity
JobPrioritymoved topg_scheduler/job_priority.pyPeriodic job functionality moved to
pg_scheduler/periodic.pyConflict resolution strategies moved to
pg_scheduler/conflict_resolution.pyVacuum policies moved to
pg_scheduler/vacuum.py
Scheduler.__init__now acceptsOptional[int]formisfire_grace_timeparameterScheduler.schedule()now accepts optionalmisfire_grace_timeparameter for per-job configurationscheduled_jobstable schema updated to includemisfire_grace_time INTEGERcolumn
Migration Notes¶
Backward Compatible: Existing code will continue to work without changes
Automatic Migration: The
misfire_grace_timecolumn is automatically added to existing tablesNo Breaking Changes: The API is fully backward compatible
0.1.0 - 2025-09-29¶
Added¶
Core Features¶
Job Scheduler: PostgreSQL-based async job scheduling system
Periodic Jobs:
@periodicdecorator for recurring tasks with automatic registrationDeduplication: Cross-replica job deduplication using deterministic job IDs
Self-rescheduling: Automatic rescheduling of periodic jobs after completion
Priority System: Support for
JobPriority.NORMALandJobPriority.CRITICALRetry Logic: Configurable retry attempts with exponential backoff
Reliability Features¶
Heartbeat Monitoring: Detect and recover from crashed workers
Orphan Recovery: Automatic cleanup of abandoned jobs
Graceful Shutdown: Wait for active jobs to complete before stopping
Lease-based Execution: Explicit job ownership with timeouts
Atomic Job Claiming: Race-condition-free job distribution
Advanced Features¶
Advisory Locks: Optional PostgreSQL advisory locks for exclusive execution
Vacuum Policies: Configurable cleanup policies for job lifecycle management
Conflict Resolution: Flexible strategies for handling duplicate job IDs
Job Management API: Runtime control of periodic jobs (enable/disable/trigger)