Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,28 @@ module Maintenance
end
```

If you want the throttle to change based on task attributes, you can define the
`throttle_on` inside `#initialize`:

```ruby
# app/tasks/maintenance/update_posts_throttled_task.rb

module Maintenance
class UpdatePostsThrottledTask < MaintenanceTasks::Task
attribute :throttle_backoff_seconds, :integer

def initialize(*)
super

throttle_on(backoff: throttle_backoff_seconds) do
DatabaseStatus.unhealthy?
end
end
# ...
end
end
```

### Custom Task Parameters

Tasks may need additional information, supplied via parameters, to run.
Expand Down
29 changes: 28 additions & 1 deletion app/models/maintenance_tasks/task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class NotFoundError < NameError; end
# backoff. Note that Tasks inherit conditions from their superclasses.
#
# @api private
class_attribute :throttle_conditions, default: []
class_attribute :throttle_conditions, default: [], instance_reader: false

# The number of active records to fetch in a single query when iterating
# over an Active Record collection task.
Expand Down Expand Up @@ -331,5 +331,32 @@ def count
def enumerator_builder(cursor:)
nil
end

# Add a condition under which this Task instance will be throttled.
#
# @param backoff [ActiveSupport::Duration, #call] a custom backoff
# can be specified. This is the time to wait before retrying the Task,
# defaulting to 30 seconds. If provided as a Duration, the backoff is
# wrapped in a proc. Alternatively,an object responding to call can be
# used. It must return an ActiveSupport::Duration.
# @yieldreturn [Boolean] where the throttle condition is being met,
# indicating that the Task should throttle.
def throttle_on(backoff: 30.seconds, &condition)
backoff_as_proc = backoff
backoff_as_proc = -> { backoff } unless backoff.respond_to?(:call)

@throttle_conditions ||= []
@throttle_conditions += [{ throttle_on: condition, backoff: backoff_as_proc }]
end

# The throttle conditions for a given Task instance. This is provided as
# an array of hashes, with each hash specifying two keys:
# throttle_condition and backoff. Note that Tasks inherit conditions from
# their superclasses.
#
# @api private
def throttle_conditions
self.class.throttle_conditions + (@throttle_conditions || [])
end
end
end
14 changes: 14 additions & 0 deletions test/models/maintenance_tasks/task_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,20 @@ class TaskTest < ActiveSupport::TestCase
Maintenance::TestTask.throttle_conditions = []
end

test "#throttle_on registers throttle condition for Task" do
throttle_condition = -> { true }

task = Maintenance::TestTask.new
task.throttle_on(&throttle_condition)

task_throttle_conditions = task.throttle_conditions
assert_equal(1, task_throttle_conditions.size)

condition = task_throttle_conditions.first
assert_equal(throttle_condition, condition[:throttle_on])
assert_equal(30.seconds, condition[:backoff].call)
end

test ".cursor_columns returns nil" do
task = Task.new
assert_nil task.cursor_columns
Expand Down
Loading