Class: MaintenanceTasks::Task

Inherits:
Object
  • Object
show all
Extended by:
ActiveSupport::DescendantsTracker
Includes:
ActiveModel::AttributeAssignment, ActiveModel::Attributes, ActiveModel::Validations, ActiveSupport::Callbacks, ActiveSupport::Rescuable
Defined in:
app/models/maintenance_tasks/task.rb

Overview

Base class that is inherited by the host application’s task classes.

Defined Under Namespace

Classes: NotFoundError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#metadataObject

Returns the value of attribute metadata.



38
39
40
# File 'app/models/maintenance_tasks/task.rb', line 38

def 
  
end

Class Method Details

.after_cancel(*filter_list, &block) ⇒ Object

Initialize a callback to run after the task is cancelled.

Parameters:



206
207
208
# File 'app/models/maintenance_tasks/task.rb', line 206

def after_cancel(*filter_list, &block)
  set_callback(:cancel, :after, *filter_list, &block)
end

.after_complete(*filter_list, &block) ⇒ Object

Initialize a callback to run after the task completes.

Parameters:



182
183
184
# File 'app/models/maintenance_tasks/task.rb', line 182

def after_complete(*filter_list, &block)
  set_callback(:complete, :after, *filter_list, &block)
end

.after_error(*filter_list, &block) ⇒ Object

Initialize a callback to run after the task produces an error.

Parameters:



214
215
216
# File 'app/models/maintenance_tasks/task.rb', line 214

def after_error(*filter_list, &block)
  set_callback(:error, :after, *filter_list, &block)
end

.after_interrupt(*filter_list, &block) ⇒ Object

Initialize a callback to run after the task is interrupted.

Parameters:



198
199
200
# File 'app/models/maintenance_tasks/task.rb', line 198

def after_interrupt(*filter_list, &block)
  set_callback(:interrupt, :after, *filter_list, &block)
end

.after_pause(*filter_list, &block) ⇒ Object

Initialize a callback to run after the task pauses.

Parameters:



190
191
192
# File 'app/models/maintenance_tasks/task.rb', line 190

def after_pause(*filter_list, &block)
  set_callback(:pause, :after, *filter_list, &block)
end

.after_start(*filter_list, &block) ⇒ Object

Initialize a callback to run after the task starts.

Parameters:



174
175
176
# File 'app/models/maintenance_tasks/task.rb', line 174

def after_start(*filter_list, &block)
  set_callback(:start, :after, *filter_list, &block)
end

.available_tasksArray<Class>

Loads and returns a list of concrete classes that inherit from the Task superclass.

Returns:

  • (Array<Class>)

    the list of classes.



71
72
73
74
75
76
77
# File 'app/models/maintenance_tasks/task.rb', line 71

def available_tasks
  warn("    MaintenanceTasks::Task.available_tasks is deprecated and will be\n    removed from maintenance-tasks 3.0.0. Use .load_all instead.\n  MSG\n  load_all\nend\n".squish, category: :deprecated)

.collectionObject

Returns the collection for this Task.

Especially useful for tests.

Returns:

  • the collection.



126
127
128
# File 'app/models/maintenance_tasks/task.rb', line 126

def collection
  new.collection
end

.collection_batch_size(size) ⇒ Object

Limit the number of records that will be fetched in a single query when iterating over an Active Record collection task.

Parameters:

  • size (Integer)

    the number of records to fetch in a single query.



159
160
161
# File 'app/models/maintenance_tasks/task.rb', line 159

def collection_batch_size(size)
  self.active_record_enumerator_batch_size = size
end

.countObject

Returns the count of items for this Task.

Especially useful for tests.

Returns:

  • the count of items.



135
136
137
# File 'app/models/maintenance_tasks/task.rb', line 135

def count
  new.count
end

.csv_collection(in_batches: nil, **csv_options) ⇒ Object

Make this Task a task that handles CSV.

An input to upload a CSV will be added in the form to start a Run. The collection and count method are implemented.

Parameters:

  • in_batches (Integer) (defaults to: nil)

    optionally, supply a batch size if the CSV should be processed in batches.

  • csv_options (Hash)

    optionally, supply options for the CSV parser. If not given, defaults to: { headers: true }

See Also:



89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'app/models/maintenance_tasks/task.rb', line 89

def csv_collection(in_batches: nil, **csv_options)
  unless defined?(ActiveStorage)
    raise NotImplementedError, "Active Storage needs to be installed\n" \
      "To resolve this issue run: bin/rails active_storage:install"
  end

  csv_options[:headers] = true unless csv_options.key?(:headers)
  csv_options[:encoding] ||= Encoding.default_external
  self.collection_builder_strategy = if in_batches
    BatchCsvCollectionBuilder.new(in_batches, **csv_options)
  else
    CsvCollectionBuilder.new(**csv_options)
  end
end

.load_allArray<Class>

Loads and returns a list of concrete classes that inherit from the Task superclass.

Returns:

  • (Array<Class>)

    the list of classes.



62
63
64
65
# File 'app/models/maintenance_tasks/task.rb', line 62

def load_all
  load_constants
  descendants
end

.mask_attribute(*attributes) ⇒ Object

Adds attribute names to sensitive arguments list.

Parameters:

  • attributes (Array<Symbol>)

    the attribute names to filter.



166
167
168
# File 'app/models/maintenance_tasks/task.rb', line 166

def mask_attribute(*attributes)
  self.masked_arguments += attributes
end

.named(name) ⇒ Task

Finds a Task with the given name.

Parameters:

  • name (String)

    the name of the Task to be found.

Returns:

  • (Task)

    the Task with the given name.

Raises:

  • (NotFoundError)

    if a Task with the given name does not exist.



48
49
50
51
52
53
54
55
56
# File 'app/models/maintenance_tasks/task.rb', line 48

def named(name)
  task = name.safe_constantize
  raise NotFoundError.new("Task #{name} not found.", name) unless task
  unless task.is_a?(Class) && task < Task
    raise NotFoundError.new("#{name} is not a Task.", name)
  end

  task
end

.no_collectionObject

Make this a Task that calls #process once, instead of iterating over a collection.



106
107
108
# File 'app/models/maintenance_tasks/task.rb', line 106

def no_collection
  self.collection_builder_strategy = MaintenanceTasks::NoCollectionBuilder.new
end

.process(*args) ⇒ Object

Processes one item.

Especially useful for tests.

Parameters:

  • args (Object, nil)

    the item to process



117
118
119
# File 'app/models/maintenance_tasks/task.rb', line 117

def process(*args)
  new.process(*args)
end

.report_on(*exceptions, **report_options) ⇒ Object

Rescue listed exceptions during an iteration and report them to the error reporter, then continue iteration.

Parameters:

  • exceptions

    list of exceptions to rescue and report

  • report_options (Hash)

    optionally, supply additional options for ‘Rails.error.report`. By default: { source: "maintenance_tasks" } or (Rails <v7.1) { handled: true }.



224
225
226
227
228
229
230
231
232
# File 'app/models/maintenance_tasks/task.rb', line 224

def report_on(*exceptions, **report_options)
  rescue_from(*exceptions) do |exception|
    if Rails.gem_version >= Gem::Version.new("7.1")
      Rails.error.report(exception, source: "maintenance_tasks", **report_options)
    else
      Rails.error.report(exception, handled: true, **report_options)
    end
  end
end

.throttle_on(backoff: 30.seconds, &condition) ⇒ Object

Add a condition under which this Task will be throttled.

Parameters:

  • backoff (ActiveSupport::Duration, #call) (defaults to: 30.seconds)

    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.

Yield Returns:

  • (Boolean)

    where the throttle condition is being met, indicating that the Task should throttle.



148
149
150
151
152
153
# File 'app/models/maintenance_tasks/task.rb', line 148

def throttle_on(backoff: 30.seconds, &condition)
  backoff_as_proc = backoff
  backoff_as_proc = -> { backoff } unless backoff.respond_to?(:call)

  self.throttle_conditions += [{ throttle_on: condition, backoff: backoff_as_proc }]
end

Instance Method Details

#collectionObject

The collection to be processed, delegated to the strategy.

Returns:

  • the collection.



279
280
281
# File 'app/models/maintenance_tasks/task.rb', line 279

def collection
  self.class.collection_builder_strategy.collection(self)
end

#countInteger?

Total count of iterations to be performed, delegated to the strategy.

Returns:

  • (Integer, nil)


309
310
311
# File 'app/models/maintenance_tasks/task.rb', line 309

def count
  self.class.collection_builder_strategy.count(self)
end

#csv_contentString

The contents of a CSV file to be processed by a Task.

Returns:

  • (String)

    the content of the CSV file to process.

Raises:

  • (NoMethodError)


247
248
249
250
251
# File 'app/models/maintenance_tasks/task.rb', line 247

def csv_content
  raise NoMethodError unless has_csv_content?

  @csv_content
end

#csv_content=(csv_content) ⇒ Object

Set the contents of a CSV file to be processed by a Task.

Parameters:

  • csv_content (String)

    the content of the CSV file to process.

Raises:

  • (NoMethodError)


256
257
258
259
260
# File 'app/models/maintenance_tasks/task.rb', line 256

def csv_content=(csv_content)
  raise NoMethodError unless has_csv_content?

  @csv_content = csv_content
end

#cursor_columnsObject

The columns used to build the ‘ORDER BY` clause of the query for iteration.

If cursor_columns returns nil, the query is ordered by the primary key. If cursor columns values change during an iteration, records may be skipped or yielded multiple times. More details in the documentation of JobIteration::EnumeratorBuilder.build_active_record_enumerator_on_records: www.rubydoc.info/gems/job-iteration/JobIteration/EnumeratorBuilder#build_active_record_enumerator_on_records-instance_method

Returns:

  • the cursor_columns.



291
292
293
# File 'app/models/maintenance_tasks/task.rb', line 291

def cursor_columns
  nil
end

#enumerator_builder(cursor:) ⇒ Enumerator

Default enumerator builder. You may override this method to return any Enumerator yielding pairs of ‘[item, item_cursor]`.

Parameters:

  • cursor (String, nil)

    cursor position to resume from, or nil on initial call.

Returns:

  • (Enumerator)


320
321
322
# File 'app/models/maintenance_tasks/task.rb', line 320

def enumerator_builder(cursor:)
  nil
end

#has_csv_content?Boolean

Returns whether the Task handles CSV.

Returns:

  • (Boolean)

    whether the Task handles CSV.



265
266
267
# File 'app/models/maintenance_tasks/task.rb', line 265

def has_csv_content?
  self.class.has_csv_content?
end

#no_collection?Boolean

Returns whether the Task is collection-less.

Returns:

  • (Boolean)

    whether the Task is collection-less.



272
273
274
# File 'app/models/maintenance_tasks/task.rb', line 272

def no_collection?
  self.class.no_collection?
end

#process(_item) ⇒ Object

Placeholder method to raise in case a subclass fails to implement the expected instance method.

Parameters:

  • _item (Object)

    the current item from the enumerator being iterated.

Raises:

  • (NotImplementedError)

    with a message advising subclasses to implement an override for this method.



302
303
304
# File 'app/models/maintenance_tasks/task.rb', line 302

def process(_item)
  raise NoMethodError, "#{self.class.name} must implement `process`."
end