celery-beat
Requires Celery 5.3+ and django-celery-beat 2.5+ for the writable backend, Python 3.11+. See the compatibility matrix for the full pin string.
Install
Section titled “Install”pip install z4j-celerybeatBackends
Section titled “Backends”| Backend | Readable | Writable |
|---|---|---|
celery.beat.PersistentScheduler (filesystem) |
✓ | ✗ (read-only) |
django_celery_beat.schedulers.DatabaseScheduler |
✓ | ✓ |
| Custom scheduler class | ✓ for its app.conf.beat_schedule entries only |
✗ (read-only) |
Writable operations
Section titled “Writable operations”When paired with django-celery-beat:
- Create: inserts into
django_celery_beat_periodictask+ appropriate*Scheduletable. - Update: modifies the row.
- Enable/Disable: flips
enabled. Pause and resume are not offered for celery-beat-owned schedules; the brain answers 409 conflict, because nothing here could hold beat's own cadence. - Delete: removes the row.
Schedule types supported
Section titled “Schedule types supported”IntervalSchedule(every N seconds/minutes/...)CrontabSchedule(minute, hour, day, month, day-of-week)SolarSchedule(sunrise/sunset) - readable as the event name; a create or update writes the event with latitude and longitude fixed at0.0ClockedSchedule(one-shot) - readable and writable; the expression is an ISO 8601clocked_time
Filesystem scheduler
Section titled “Filesystem scheduler”If you're using the default PersistentScheduler, the dashboard shows schedules as read-only. Switch to DatabaseScheduler to edit from the UI.
Multiple beat processes
Section titled “Multiple beat processes”Running multiple beat schedulers against the same backend causes duplicate task firings. z4j does not detect a second beat process. Run exactly one beat.
Caveats
Section titled “Caveats”- The agent writes to the DB directly (bypassing
PeriodicTask.save_related-style cascades). No Django-specific validators run. Create and update go through model saves (PeriodicTask.objects.createandrow.save()), sopost_savefires. Delete is a querysetdelete(), which still emitspost_deleteper row. Enable and disable are a querysetupdate(enabled=...), which calls nosave()and fires no signals. - The adapter never calls
PeriodicTasks.update_changed(); how quickly beat notices each change is up to django-celery-beat's own change tracking.