Class: Wurk::IterableJob::ActiveRecordEnumerator

Inherits:
Object
  • Object
show all
Defined in:
lib/wurk/iterable_job/active_record_enumerator.rb

Overview

Cursor-resumable ActiveRecord iteration helpers for IterableJob#build_enumerator. Behavior parity with Sidekiq's Sidekiq::Job::Iterable::ActiveRecordEnumerator: the cursor is the primary key of the last-yielded record, threaded back through AR's start: so iteration resumes after an interruption without re-scanning.

ActiveRecord is NOT a wurk dependency โ€” these methods simply call the relation's batching API, so they work when the host app has AR and raise a plain NoMethodError otherwise (you can't build a relation without AR).

Spec: docs/target/sidekiq-free.md ยง6.4; Sidekiq wiki Iteration.

Instance Method Summary collapse

Constructor Details

#initialize(relation, cursor: nil, **options) ⇒ ActiveRecordEnumerator

Returns a new instance of ActiveRecordEnumerator.



17
18
19
20
21
# File 'lib/wurk/iterable_job/active_record_enumerator.rb', line 17

def initialize(relation, cursor: nil, **options)
  @relation = relation
  @cursor = cursor
  @options = options
end

Instance Method Details

#batchesObject

[records_batch, batch.first.id] pairs. The size lambda is the record count, NOT the batch count โ€” byte-for-byte with upstream Sidekiq's ActiveRecordEnumerator#batches, so enum.size returns the same value a drop-in app gets from Sidekiq. (Only the lazy #size differs from relations; the run loop never calls it.)



37
38
39
40
41
42
43
# File 'lib/wurk/iterable_job/active_record_enumerator.rb', line 37

def batches
  ::Enumerator.new(-> { @relation.count }) do |yielder|
    @relation.find_in_batches(**@options, start: @cursor) do |batch|
      yielder.yield(batch, batch.first.id)
    end
  end
end

#recordsObject

[record, record.id] pairs.



24
25
26
27
28
29
30
# File 'lib/wurk/iterable_job/active_record_enumerator.rb', line 24

def records
  ::Enumerator.new(-> { @relation.count }) do |yielder|
    @relation.find_each(**@options, start: @cursor) do |record|
      yielder.yield(record, record.id)
    end
  end
end

#relationsObject

[relation, first_record.id] pairs. :batch_size is normalized to :of so callers use one option name across all three helpers. Delete :batch_size unconditionally before the ||= so a caller passing both :of and :batch_size can't leak :batch_size into in_batches (which has no such keyword) โ€” upstream's ||= short-circuits and raises ArgumentError there; valid single-option calls are unaffected.



51
52
53
54
55
56
57
58
59
60
61
# File 'lib/wurk/iterable_job/active_record_enumerator.rb', line 51

def relations
  ::Enumerator.new(-> { relations_size }) do |yielder|
    options = @options.dup
    batch_size = options.delete(:batch_size)
    options[:of] ||= batch_size

    @relation.in_batches(**options, start: @cursor) do |relation|
      yielder.yield(relation, relation.first.id)
    end
  end
end