module Syncable extend ActiveSupport::Concern included do has_many :syncs, as: :syncable, dependent: :destroy end def syncing? raise NotImplementedError, "Subclasses must implement the syncing? method" end # Schedules a sync for syncable. If there is an existing sync pending/syncing for this syncable, # we do not create a new sync, and attempt to expand the sync window if needed. def sync_later(parent_sync: nil, window_start_date: nil, window_end_date: nil) Sync.transaction do with_lock do sync = self.syncs.incomplete.first if sync Rails.logger.info("There is an existing sync, expanding window if needed (#{sync.id})") sync.expand_window_if_needed(window_start_date, window_end_date) else sync = self.syncs.create!( parent: parent_sync, window_start_date: window_start_date, window_end_date: window_end_date ) SyncJob.perform_later(sync) end sync end end end def perform_sync(sync) syncer.perform_sync(sync) end def perform_post_sync syncer.perform_post_sync end def broadcast_sync_complete sync_broadcaster.broadcast end def sync_error latest_sync&.error end def last_synced_at latest_sync&.completed_at end def last_sync_created_at latest_sync&.created_at end private def latest_sync syncs.ordered.first end def syncer self.class::Syncer.new(self) end def sync_broadcaster self.class::SyncCompleteEvent.new(self) end end