Skip to content

feat(schedulers): add StrictDatabaseScheduler that disables unknown tasks#1034

Open
serl wants to merge 2 commits into
celery:mainfrom
serl:feat/strict-database-scheduler
Open

feat(schedulers): add StrictDatabaseScheduler that disables unknown tasks#1034
serl wants to merge 2 commits into
celery:mainfrom
serl:feat/strict-database-scheduler

Conversation

@serl

@serl serl commented Apr 30, 2026

Copy link
Copy Markdown

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

…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

codecov Bot commented Apr 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.76%. Comparing base (99f7bcf) to head (a0fbaba).

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 of DatabaseScheduler) that disables unregistered tasks on startup.
  • Add an entry-point alias (django_strict) for selecting the new scheduler via celery 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.

Comment thread django_celery_beat/schedulers.py Outdated
Comment on lines +564 to +571
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()

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How large the installation would be to encounter this problem?

Comment thread t/unit/test_schedulers.py
Comment on lines +1433 to +1439
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>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 StrictDatabaseScheduler in django_celery_beat.schedulers.
  • Exposes the scheduler via a new celery.beat_schedulers entry 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.

Comment on lines +559 to +562
def setup_schedule(self):
self._disable_unknown_tasks()
super().setup_schedule()

Comment on lines +564 to +571
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()
Comment thread t/unit/test_schedulers.py
Comment on lines +1440 to +1441


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants