Dry-run Database Scheduler#968
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a DryRunDatabaseScheduler class that reads periodic tasks from the database while operating in dry-run mode, preventing task execution in development environments. This addresses issue #942 by allowing developers to test scheduler configuration without triggering actual task execution.
Changes:
- Added new
DryRunDatabaseSchedulerclass that inherits fromDatabaseScheduler - Overrides
apply_entrymethod to log scheduled tasks instead of executing them
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| class DryRunDatabaseScheduler(DatabaseScheduler): | ||
| """ | ||
| DatabaseScheduler in dry-run mode. | ||
|
|
||
| The Scheduler reads Periodic Tasks from the database but does not execute them, | ||
| only logging when they would have been triggered. | ||
| Useful in environments where tasks should not actually run, but the scheduler | ||
| must remain operational. | ||
| """ | ||
|
|
||
| def apply_entry(self, entry, producer=None): | ||
| """ | ||
| Overwritten method to log the triggered tasks instead of actually running it. | ||
| """ | ||
| debug( | ||
| 'Dry-run mode: Skipping task %s %s %s', | ||
| entry.task, | ||
| entry.args, | ||
| entry.kwargs | ||
| ) |
There was a problem hiding this comment.
The new DryRunDatabaseScheduler class lacks test coverage. Given that the repository has comprehensive test coverage for the DatabaseScheduler (in t/unit/test_schedulers.py), tests should be added to verify the dry-run behavior, including confirming that tasks are logged but not executed, and that the scheduler functions correctly without affecting task execution.
| class DryRunDatabaseScheduler(DatabaseScheduler): | ||
| """ | ||
| DatabaseScheduler in dry-run mode. | ||
|
|
||
| The Scheduler reads Periodic Tasks from the database but does not execute them, | ||
| only logging when they would have been triggered. | ||
| Useful in environments where tasks should not actually run, but the scheduler | ||
| must remain operational. | ||
| """ | ||
|
|
||
| def apply_entry(self, entry, producer=None): | ||
| """ | ||
| Overwritten method to log the triggered tasks instead of actually running it. | ||
| """ | ||
| debug( | ||
| 'Dry-run mode: Skipping task %s %s %s', | ||
| entry.task, | ||
| entry.args, | ||
| entry.kwargs | ||
| ) |
There was a problem hiding this comment.
Documentation is missing for the new DryRunDatabaseScheduler. Consider adding usage examples to the documentation (such as in docs/includes/introduction.txt) showing how to configure and use the dry-run scheduler, similar to how the DatabaseScheduler is documented. Users should know how to enable this scheduler in their development environments.
auvipy
left a comment
There was a problem hiding this comment.
Interesting stuff! but we will need tests and some times to decided before merging this
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #968 +/- ##
==========================================
+ Coverage 87.64% 87.70% +0.06%
==========================================
Files 32 32
Lines 1012 1017 +5
Branches 81 81
==========================================
+ Hits 887 892 +5
Misses 107 107
Partials 18 18 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
This will need to be rebased to the current |
81a5d2c to
6c3e2b6
Compare
| entry.kwargs | ||
| ) | ||
|
|
||
| def sync(self): |
There was a problem hiding this comment.
@auvipy , thanks for this suggestion.
I understand that we are skipping the metadata update in dry-run mode since the task wasn't actually executed. But don't we need to store the attempt of execution to prevent breaking the scheduler loop? For an hourly task, for example, don't we want to persist the execution attempt?
If not, it will only be stored in memory, right? Any refresh of the tasks in the event loop will confuse the scheduler.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
78c8222 to
422f88c
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def sync(self): | ||
| """ | ||
| Override sync to avoid persisting execution metadata in dry-run mode. | ||
|
|
||
| In DatabaseScheduler, sync() saves dirty entries (including updated | ||
| last_run_at and total_run_count) back to the database. For a dry-run | ||
| scheduler this would be misleading, since tasks are never actually run. | ||
|
|
||
| By overriding sync as a no-op, we ensure that dry-run operation does not | ||
| modify PeriodicTask records in the database while still allowing the | ||
| scheduler machinery to operate normally. | ||
| """ | ||
| debug('Dry-run mode: Skipping database sync of scheduled tasks.') |
|
|
||
|
|
Description
Introduces the
DryRunDatabaseSchedulerto read Periodic Tasks from the database while operating in dry-run mode.The dry-run mode is useful for setting up projects with Periodic Tasks stored in the Django database while skipping their execution in development environments lower than production, such as local environments.
The Scheduler class inherits from
DatabaseSchedulerand overwrites theapply_entrymethod to log the triggered tasks instead of actually running them.Fixes: #942