Skip to content

Commit

Permalink
Add while enumerator
Browse files Browse the repository at this point in the history
  • Loading branch information
angeloocana committed Jan 3, 2024
1 parent 44b95d2 commit f0d26be
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- [437](https://github.com/Shopify/job-iteration/pull/437) - Use minimum between per-class `job_iteration_max_job_runtime` and `JobIteration.max_job_runtime`, instead of enforcing only setting decreasing values.
Because it is possible to change the global or parent values after setting the value on a class, it is not possible to truly enforce the decreasing value constraint. Instead, we now use the minimum between the global value and per-class value. This is considered a non-breaking change, as it should not break any **existing** code, it only removes the constraint on new classes.
- [446](https://github.com/Shopify/job-iteration/pull/446) - Support while loop enumerator

### Bug fixes

Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,25 @@ class NestedIterationJob < ApplicationJob
end
```


```ruby
class DeleteXyzJob < ApplicationJob
include JobIteration::Iteration

def build_enumerator(params)
enumerator_builder.while query_model_xyz(params).exists?
end

def each_iteration(count, params)
query_model_xyz(params).limit(1000).delete_all
end

def query_model_xyz(params)
Xyz.where(owner_id: params[:owner_id])
end
end
```

Iteration hooks into Sidekiq and Resque out of the box to support graceful interruption. No extra configuration is required.

## Guides
Expand Down
25 changes: 25 additions & 0 deletions lib/job-iteration/enumerator_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,30 @@ def build_nested_enumerator(enums, cursor:)
NestedEnumerator.new(enums, cursor: cursor).each
end

# Builds Enumerator for while loop iteration.
#
# @yield Condition to be evaluated before each iteration, the iteration is allowed if a true value is returned.
#
# @example
# def build_enumerator(params)
# enumerator_builder.while query_model_xyz(params).exists?
# end
#
# def each_iteration(count, params)
# query_model_xyz(params).limit(1000).delete_all
# end
#
# def query_model_xyz(params)
# Xyz.where(owner_id: params[:owner_id])
# end
#
def build_while_enumerator(&condition)
count = 0
Enumerator.new do |yielder|
yielder << count += 1 while condition.call
end
end

alias_method :once, :build_once_enumerator
alias_method :times, :build_times_enumerator
alias_method :array, :build_array_enumerator
Expand All @@ -190,6 +214,7 @@ def build_nested_enumerator(enums, cursor:)
alias_method :throttle, :build_throttle_enumerator
alias_method :csv, :build_csv_enumerator
alias_method :nested, :build_nested_enumerator
alias_method :while, :build_while_enumerator

private

Expand Down
9 changes: 9 additions & 0 deletions test/unit/enumerator_builder_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ class EnumeratorBuilderTest < ActiveSupport::TestCase
)
end

test_builder_method(:build_while_enumerator) do
count = 0
enum = enumerator_builder(wraps: 0).build_while_enumerator do
count < 3 ? (count += 1) : false
end

assert_equal [1, 2, 3], enum.to_a
end

# checks that all the non-alias methods were tested
raise "methods not tested: #{methods.inspect}" unless methods.empty?

Expand Down

0 comments on commit f0d26be

Please sign in to comment.