Class: ActiveRecord::Materialized::Reconciler Private
- Inherits:
-
Object
- Object
- ActiveRecord::Materialized::Reconciler
- Defined in:
- lib/activerecord/materialized/reconciler.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
Bounds a view's staleness in time: verifies its materialized contents against the source (via DataVerifier) and repairs whatever the change source missed, using SCOPED maintenance — never a full rebuild. Meant to run on a schedule as a backstop for writes any change source can miss (a bulk/raw write, a dropped or lagging CDC event).
Safe alongside normal refresh. It drains pending maintenance first, so remaining drift is genuinely missed writes rather than un-applied maintenance, then repairs through the same guarded, transactional maintenance path. When a refresh is already in flight it defers to the next tick rather than verifying a cache mid-mutation or racing that cycle's payload — so it can neither corrupt the cache nor double-maintain.
Instance Method Summary collapse
-
#initialize(view_class, mode: :checksum, sample: nil) ⇒ Reconciler
constructor
private
A new instance of Reconciler.
- #reconcile! ⇒ Object private
Constructor Details
#initialize(view_class, mode: :checksum, sample: nil) ⇒ Reconciler
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new instance of Reconciler.
20 21 22 23 24 |
# File 'lib/activerecord/materialized/reconciler.rb', line 20 def initialize(view_class, mode: :checksum, sample: nil) @view_class = view_class @mode = mode @sample = sample end |
Instance Method Details
#reconcile! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/activerecord/materialized/reconciler.rb', line 26 def reconcile! # Route the whole cycle to the writer so the repair writes (merge!/mark_reconciled!/refresh!) # land on the primary; DataVerifier.verify nests its own reading role, so verification still # reads from the replica while repair stays on the primary. ConnectionRouting.maintenance do divergent = [] next emit(build) unless @view_class.materialized? # cold view: no cache to verify or repair @view_class.refresh! # drain pending maintenance so any remaining drift is genuine divergent = detect_drift repair!(divergent) unless divergent.empty? mark_reconciled!(divergent) emit(build(repaired_keys: divergent)) rescue Refresher::AlreadyRefreshingError # A live refresh owns the cycle; the scoped repair we queued (if any) drains on # that cycle or the next tick. Defer without corrupting or double-maintaining. emit(build(repaired_keys: divergent || [], deferred: true)) end end |