Skip to content

Conversation

@zenodallavalle
Copy link

Implement unique constraints for the ClockedSchedule and CrontabSchedule models to prevent race conditions and duplicate entries when using get_or_create under concurrent workers. This change ensures that only one instance of each schedule can be created, addressing the issue of duplicated schedule entries.

Fixes #980 and #701.

@zenodallavalle zenodallavalle marked this pull request as ready for review December 9, 2025 11:34
@auvipy auvipy requested review from auvipy and Copilot December 9, 2025 13:45
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds unique constraints to the IntervalSchedule, ClockedSchedule, and CrontabSchedule models to prevent race conditions and duplicate entries when using get_or_create under concurrent workers. The changes bring these models in line with the existing SolarSchedule model, which already uses unique_together. The PR addresses issues #980 and #701 related to duplicate schedule entries.

Key changes:

  • Added UniqueConstraint on every and period fields for IntervalSchedule
  • Added unique=True to the clocked_time field for ClockedSchedule
  • Added UniqueConstraint on all scheduling fields (minute, hour, day_of_month, month_of_year, day_of_week, timezone) for CrontabSchedule

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
django_celery_beat/models.py Added unique constraints to IntervalSchedule, ClockedSchedule, and CrontabSchedule models to prevent duplicate schedule entries
django_celery_beat/migrations/0020_alter_clockedschedule_clocked_time_and_more.py Database migration to apply the unique constraints and alter the ClockedSchedule.clocked_time field

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +176 to +178
constraints = [
models.UniqueConstraint(fields=["every", "period"], name="unique_interval")
]
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The unique constraints added by this PR will prevent the creation of duplicate schedules, but the existing test _test_duplicate_schedules in t/unit/test_models.py expects to be able to create duplicates (line 77 creates a second instance with the same kwargs, and line 78 expects 2 instances to exist). These tests will now fail with IntegrityError when trying to create the second duplicate instance. The tests need to be updated to either:

  1. Test that duplicates are prevented (expect IntegrityError)
  2. Use different kwargs for the second instance
  3. Test that from_schedule properly handles uniqueness with get_or_create

Copilot uses AI. Check for mistakes.
help_text=_('Run the task at clocked time'),
verbose_name=_("Clock Time"),
help_text=_("Run the task at clocked time"),
unique=True,
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The unique constraint on clocked_time will prevent the creation of duplicate schedules, but the existing test test_duplicate_schedules in ClockedScheduleTestCase (t/unit/test_models.py, line 148-150) expects to be able to create duplicates. This test will now fail with IntegrityError. The test needs to be updated to verify that the unique constraint works correctly.

Copilot uses AI. Check for mistakes.
Comment on lines +321 to +333
constraints = [
models.UniqueConstraint(
fields=[
"minute",
"hour",
"day_of_month",
"month_of_year",
"day_of_week",
"timezone",
],
name="unique_crontab",
)
]
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The unique constraint on CrontabSchedule will prevent the creation of duplicate schedules, but the existing test test_duplicate_schedules in CrontabScheduleTestCase (t/unit/test_models.py, line 99-109) expects to be able to create duplicates. This test will now fail with IntegrityError. The test needs to be updated to verify that the unique constraint works correctly.

Copilot uses AI. Check for mistakes.
Copy link
Member

@auvipy auvipy left a comment

Choose a reason for hiding this comment

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

can you please check the comments and test failures in the CI

@zenodallavalle
Copy link
Author

Thanks for the feedback. Before adjusting the tests, I think it would be useful to have a broader discussion about the implications of adding these uniqueness constraints.

At the moment, the test suite explicitly allows the creation of duplicate schedule instances, which suggests that the current behavior is either intentional or at least tolerated for backward-compatibility reasons. Introducing strict uniqueness rules would change that contract, and may impact existing installations that rely on the current behavior—especially where duplicate rows may already exist in production databases.

My PR was meant as an indicative proposal to address the race-condition issues reported in #980 and schedule uniqueness requested in #701, not as a final decision. As @sevdog noted in #701, the tuple of fields in CrontabSchedule (and similarly in the other schedule models) is conceptually meant to identify a single schedule instance. If that tuple is not unique, then multiple identical rows can coexist and the table becomes more of a loose validation helper rather than a true normalized representation of schedules. This aligns with the idea that—if duplication is intentional or required—it should ideally be configurable rather than the default behavior. The changes themselves make sense from a concurrency and data-integrity standpoint, but they should be evaluated in light of:
• Backward compatibility with existing deployments
• Expected behavior of the API (given the current tests)
• Whether strict uniqueness is the direction the project wants to take

Once there is agreement on the intended behavior moving forward, I’d be happy to contribute. In any case, I suggest we make a collective decision on this point and update the documentation so that users clearly understand the expected behavior and the reasoning behind it.

Let me know how you’d like to proceed.

@auvipy
Copy link
Member

auvipy commented Dec 10, 2025

we need time to decide on that.

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.

Race condition when using get_or_create for ClockedSchedule causes duplicated schedule entries under concurrent workers

2 participants