Skip to content

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.

Terminal window
pip install z4j-celerybeat
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)

When paired with django-celery-beat:

  • Create: inserts into django_celery_beat_periodictask + appropriate *Schedule table.
  • 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.
  • 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 at 0.0
  • ClockedSchedule (one-shot) - readable and writable; the expression is an ISO 8601 clocked_time

If you're using the default PersistentScheduler, the dashboard shows schedules as read-only. Switch to DatabaseScheduler to edit from the UI.

Running multiple beat schedulers against the same backend causes duplicate task firings. z4j does not detect a second beat process. Run exactly one beat.

  • 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.create and row.save()), so post_save fires. Delete is a queryset delete(), which still emits post_delete per row. Enable and disable are a queryset update(enabled=...), which calls no save() 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.