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