Skip to content

Fix RecordNotUnique crash on concurrent sync attempt creation - #220

Merged
mmenanno merged 2 commits into
mainfrom
fix-open-issues
Sep 3, 2026
Merged

Fix RecordNotUnique crash on concurrent sync attempt creation#220
mmenanno merged 2 commits into
mainfrom
fix-open-issues

Conversation

@mmenanno

@mmenanno mmenanno commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • CalendarSource#schedule_sync already rescues ActiveRecord::RecordNotUnique raised by the idx_unique_active_sync_attempt_per_source partial unique index (only one active queued/running SyncAttempt per source), but two other code paths that create a queued SyncAttempt directly did not have that protection.
  • SyncAttemptManageable#find_or_create_sync_attempt (used by SyncCalendarJob when called without an attempt_id — e.g. from EventMapping#schedule_affected_syncs — and by PushStateJob) now rescues the race and reuses the existing active attempt instead of crashing.
  • AutoSyncScheduler#schedule_syncs now rescues the same race (which can occur between find_sources_due_for_sync and the per-source create!) and simply skips that source, since it's already covered by the other in-flight attempt.

Fixes #119, which was a recurring Honeybadger crash: ActiveRecord::RecordNotUnique: SQLite3::ConstraintException: UNIQUE constraint failed: sync_attempts.calendar_source_id.

Test plan

  • Added a SyncCalendarJob test simulating a concurrent worker winning the race, asserting the job reuses the existing attempt instead of raising.
  • Added an AutoSyncScheduler test simulating a concurrent attempt created between find_sources_due_for_sync and schedule_syncs, asserting that source is skipped and the other source still gets scheduled.
  • bin/rails test (full suite, 1005 runs) passes.
  • bundle exec rubocop on changed files — no new offenses.

CalendarSource#schedule_sync already rescues ActiveRecord::RecordNotUnique
from the idx_unique_active_sync_attempt_per_source partial index, but two
other code paths that create a queued SyncAttempt directly did not:
SyncAttemptManageable#find_or_create_sync_attempt (used by SyncCalendarJob
when invoked without an attempt_id, e.g. from EventMapping, and by
PushStateJob) and AutoSyncScheduler#schedule_syncs. A concurrent sync for
the same source could hit the unique constraint and crash the job.

Fixes #119
@mmenanno
mmenanno merged commit 649fe38 into main Sep 3, 2026
11 checks passed
@mmenanno
mmenanno deleted the fix-open-issues branch September 3, 2026 00:33
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.

[Calendar Hub/production] ActiveRecord::RecordNotUnique: SQLite3::ConstraintException: UNIQUE constraint failed: sync_attempts.calendar_source_id

1 participant