feat(schedulers): add StrictDatabaseScheduler that disables unknown tasks#1034
feat(schedulers): add StrictDatabaseScheduler that disables unknown tasks#1034serl wants to merge 2 commits into
Conversation
…asks Adds a new DatabaseScheduler subclass that, at startup, disables any enabled PeriodicTask whose dotted task name is not registered with the running Celery app. This addresses the common operational pain point where tasks are removed from the codebase but their database rows linger with enabled=True, causing beat to keep dispatching them and workers to log NotRegistered errors indefinitely. The new scheduler is exposed both as a class (django_celery_beat.schedulers:StrictDatabaseScheduler) and as a celery beat-scheduler entry point alias (django_strict). Disabled rows are not deleted; they can be re-enabled from the admin if the task name becomes registered again.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1034 +/- ##
==========================================
+ Coverage 87.64% 87.76% +0.12%
==========================================
Files 32 32
Lines 1012 1022 +10
Branches 81 83 +2
==========================================
+ Hits 887 897 +10
Misses 107 107
Partials 18 18 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds an opt-in “strict” variant of the database-backed Celery beat scheduler that proactively disables enabled PeriodicTask rows whose task name isn’t registered in the running Celery app, reducing persistent NotRegistered noise after tasks are removed from the codebase.
Changes:
- Introduce
StrictDatabaseScheduler(subclass ofDatabaseScheduler) that disables unregistered tasks on startup. - Add an entry-point alias (
django_strict) for selecting the new scheduler viacelery beat -S .... - Add documentation and a unit test covering the disable-on-startup behavior.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
django_celery_beat/schedulers.py |
Adds StrictDatabaseScheduler and startup disable logic for unknown tasks. |
setup.py |
Registers the scheduler under the celery.beat_schedulers entry point as django_strict. |
docs/includes/introduction.txt |
Documents when to use strict vs default scheduler and notes the alias. |
t/unit/test_schedulers.py |
Adds a unit test verifying unknown tasks are disabled. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| for task in self.Model.objects.enabled(): | ||
| if task.task not in self.app.tasks: | ||
| warning( | ||
| 'Disabling unregistered periodic task %r (task=%r)', | ||
| task.name, task.task, | ||
| ) | ||
| task.enabled = False | ||
| task.save() |
There was a problem hiding this comment.
How large the installation would be to encounter this problem?
| self.Scheduler(app=self.app) | ||
|
|
||
| self.unknown.refresh_from_db() | ||
| assert self.unknown.enabled is False | ||
|
|
||
| self.known.refresh_from_db() | ||
| assert self.known.enabled is True |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds an opt-in “strict” variant of the database-backed Celery beat scheduler that automatically disables enabled PeriodicTask rows whose task names are not registered in the running Celery app, reducing persistent NotRegistered noise after tasks are removed.
Changes:
- Introduces
StrictDatabaseSchedulerindjango_celery_beat.schedulers. - Exposes the scheduler via a new
celery.beat_schedulersentry point alias (django_strict) and documents when to use it. - Adds a unit test covering disabling of an unknown DB task.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
django_celery_beat/schedulers.py |
Adds StrictDatabaseScheduler that disables unregistered periodic tasks on startup. |
t/unit/test_schedulers.py |
Adds a test asserting unknown DB task rows are disabled on scheduler init. |
setup.py |
Registers django_strict beat scheduler entry point. |
docs/includes/introduction.txt |
Documents choosing between DatabaseScheduler vs StrictDatabaseScheduler. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def setup_schedule(self): | ||
| self._disable_unknown_tasks() | ||
| super().setup_schedule() | ||
|
|
| for task in self.Model.objects.enabled(): | ||
| if task.task not in self.app.tasks: | ||
| warning( | ||
| 'Disabling unregistered periodic task %r (task=%r)', | ||
| task.name, task.task, | ||
| ) | ||
| task.enabled = False | ||
| task.save() |
|
|
||
|
|
Adds a new DatabaseScheduler subclass that, at startup, disables any enabled PeriodicTask whose dotted task name is not registered with the running Celery app. This addresses the common operational pain point where tasks are removed from the codebase but their database rows linger with enabled=True, causing beat to keep dispatching them and workers to log NotRegistered errors indefinitely.
The new scheduler is exposed both as a class
(django_celery_beat.schedulers:StrictDatabaseScheduler) and as a celery beat-scheduler entry point alias (django_strict). Disabled rows are not deleted; they can be re-enabled from the admin if the task name becomes registered again.
It's a partial fix to #248 #654, or at least it is for our specific case: removing a scheduled task and its definition.
It does not, however, disable schedules that point to currently existing tasks, while it disable schedules that are currently in the configuration but point to non-existing tasks.
EDIT:
In case this gets accepted, the doc should be updated accordingly