### Example Task Defining a Collection
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task.md
This example demonstrates overriding `collection` to fetch and process featured posts.
```ruby
class Maintenance::UpdatePostsTask < MaintenanceTasks::Task
def collection
Post.where(featured: false).order(:id)
end
def process(post)
post.update!(featured: true) if post.high_quality?
end
end
```
--------------------------------
### Example: Get Task Status
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Shows examples of retrieving the status for a task.
```ruby
task_data.status # "running"
task_data.status # "new"
```
--------------------------------
### Install Maintenance Tasks
Source: https://github.com/shopify/maintenance_tasks/blob/main/README.md
Run this command to install the maintenance tasks gem and its associated migrations.
```sh-session
bin/rails generate maintenance_tasks:install
```
--------------------------------
### started?
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/run.md
Returns whether the run has started its execution.
```APIDOC
## started?
### Description
Returns whether the run has started execution.
### Method
`started?`
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
None
### Request Example
```ruby
if !run.started?
puts "Still waiting to be picked up"
end
```
### Response
#### Success Response
- **Boolean** - True if the run has started, false otherwise.
#### Response Example
None
```
--------------------------------
### Example Task with Custom Processing Logic
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task.md
This example shows a `BackfillTask` that overrides the `process` method to update user records.
```ruby
class Maintenance::BackfillTask < MaintenanceTasks::Task
def collection
User.where(name: nil)
end
def process(user)
user.update!(name: user.email.split('@').first)
end
end
```
--------------------------------
### Install maintenance_tasks CLI
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/cli.md
Install the CLI executable using the gem command. Alternatively, use Bundler for project-specific installations.
```bash
gem install maintenance_tasks
```
```bash
bundle exec maintenance_tasks [command]
```
--------------------------------
### Example Task with Composite Key Cursor Columns
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task.md
This example demonstrates using `cursor_columns` with a composite key for ordered iteration.
```ruby
class Maintenance::IterateWithCompositeKeyTask < MaintenanceTasks::Task
def collection
Record.all
end
def cursor_columns
[:user_id, :id] # For composite key ordering
end
def process(record)
record.update!(processed: true)
end
end
```
--------------------------------
### Example Task with Completion and Error Callbacks
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task.md
This example shows how to implement a custom task with `after_complete` and `after_error` callbacks for notifications.
```ruby
class Maintenance::NotificationTask < MaintenanceTasks::Task
after_complete do
NotificationService.notify("Task completed!")
end
after_error do
NotificationService.alert("Task failed!")
end
def collection
User.all
end
def process(user)
user.notify
end
end
```
--------------------------------
### start
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/run.md
Sets the started_at timestamp and tick_total count, then executes :start callbacks. Requires the total expected iterations as an argument.
```APIDOC
## start
### Description
Sets started_at timestamp and tick_total count, then executes :start callbacks.
### Method
`start(count)`
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
None
### Parameters
#### Standard Parameters
- **count** (Integer) - Required - Total expected iterations
### Request Example
```ruby
run.start(500) # Expects 500 iterations
```
### Response
#### Success Response
- **void**
#### Response Example
None
```
--------------------------------
### Start a Run
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/run.md
Initializes a run by setting the started_at timestamp and the total expected tick count, then executes any associated :start callbacks.
```ruby
run.start(500) # Expects 500 iterations
```
--------------------------------
### View Usage Example
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/runs-page.md
Provides an example of how to display paginated run records and a 'Next Page' link in a Rails view.
```erb
<% @runs.each do |run|
%>
<%= run.task_name %>
Status: <%= run.status %>
Started: <%= run.started_at %>
<% end %>
```
--------------------------------
### Example: Create a RunsPage Instance
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/runs-page.md
Demonstrates how to instantiate RunsPage with a relation of runs and a nil cursor for the first page.
```ruby
all_runs = MaintenanceTasks::Run.where(task_name: "MyTask").order(created_at: :desc)
page = MaintenanceTasks::RunsPage.new(all_runs, cursor: nil)
```
--------------------------------
### Example: Group Available Tasks by Category
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Demonstrates how to retrieve all tasks and group them by their category.
```ruby
all_tasks = MaintenanceTasks::TaskDataIndex.available_tasks
tasks_by_category = all_tasks.group_by(&:category)
# => {
# active: [TaskDataIndex, ...],
# completed: [TaskDataIndex, ...],
# new: [TaskDataIndex, ...]
# }
```
--------------------------------
### Example: Group Tasks by Category in UI
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Demonstrates how to fetch available tasks and group them by category for display purposes.
```ruby
tasks = MaintenanceTasks::TaskDataIndex.available_tasks
tasks.group_by(&:category)
# => {
# active: [...],
# new: [...],
# completed: [...]
# }
```
--------------------------------
### CSV File Attachable Hash Example
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/types.md
Example of creating and using the `csv_file` hash with `MaintenanceTasks::Runner.run`.
```ruby
csv_file = {
io: File.open('users.csv'),
filename: 'users.csv',
content_type: 'text/csv'
}
MaintenanceTasks::Runner.run(
name: "ImportTask",
csv_file: csv_file
)
```
--------------------------------
### on_start
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-job.md
Called when iteration begins. It calculates the total count, marks the run as started, and triggers the Task's start callbacks.
```APIDOC
## Private Method: on_start
### Description
Called when iteration begins.
### Signature
```ruby
def on_start -> void
```
### Behavior:
- Gets count from task or enumerator
- Calls `run.start(count)` to set started_at and tick_total
- Triggers Task's `:start` callbacks
```
--------------------------------
### CsvCollectionBuilder Task Example
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/collection-builders.md
Example of configuring a task to use `csv_collection` with specific CSV parsing options.
```ruby
class Maintenance::ImportTask < MaintenanceTasks::Task
csv_collection headers: true, encoding: 'UTF-8'
def process(row)
User.create!(row.to_h)
end
end
```
--------------------------------
### Install Maintenance Tasks Gem
Source: https://github.com/shopify/maintenance_tasks/blob/main/README.md
Add the gem to your project and run the install generator to set up the necessary database tables and routes.
```sh
bundle add maintenance_tasks
bin/rails generate maintenance_tasks:install
```
--------------------------------
### Example HTML Output for Progress
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/progress.md
Shows the resulting HTML structure and content generated by the view helper integration for progress display.
```html
Processed 250 out of 1,000 items (25%).
```
--------------------------------
### Controller Actions for Task Index and Show
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Provides example controller actions for displaying a list of tasks and preparing a specific task for display, including handling parameters and arguments.
```ruby
class TasksController < ApplicationController
def index
@available_tasks = MaintenanceTasks::TaskDataIndex.available_tasks
@grouped_tasks = @available_tasks.group_by(&:category)
end
def show
@task = MaintenanceTasks::TaskDataShow.prepare(
params[:id],
runs_cursor: params[:cursor],
arguments: params.permit!.to_h
)
end
end
```
--------------------------------
### Example Task with Custom Count Method
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task.md
This example shows a task that defines a custom `count` method for progress estimation.
```ruby
class Maintenance::CustomCountTask < MaintenanceTasks::Task
def collection
User.all
end
def count
User.count # Optional: return nil to skip progress estimation
end
def process(user)
user.touch
end
end
```
--------------------------------
### BatchCsvCollectionBuilder Task Example
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/collection-builders.md
Example of configuring a task to use `csv_collection` with batch processing and specific CSV options.
```ruby
class Maintenance::ImportTask < MaintenanceTasks::Task
csv_collection in_batches: 100, encoding: 'UTF-8'
def process(batch)
records = batch.map(&:to_h)
User.insert_all(records)
end
end
```
--------------------------------
### Example Task Reporting Specific Exceptions
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task.md
This example demonstrates using `report_on` to handle `Timeout::Error` and `ApiError` during API synchronization.
```ruby
class Maintenance::ApiSyncTask < MaintenanceTasks::Task
report_on(Timeout::Error, ApiError)
def collection
Record.all
end
def process(record)
record.sync_with_api # May raise ApiError
end
end
```
--------------------------------
### Task.after_start
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task.md
Registers a callback to run after the task starts. This allows for custom logic to be executed at the beginning of a task.
```APIDOC
## Task.after_start
### Description
Register a callback to run after the task starts.
### Method
Instance Method
### Parameters
#### Path Parameters
- **filter_list** (Array) - Optional - List of filters
- **block** (Proc) - Required - Callback block
```
--------------------------------
### Notification Event Subscription Example
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/types.md
Example of subscribing to ActiveSupport notifications for maintenance tasks using a regular expression to match event names.
```ruby
ActiveSupport::Notifications.subscribe /\.maintenance_tasks\z/ do |name, start, finish, id, payload|
# name: "succeeded.maintenance_tasks"
# payload: {run_id, job_id, task_name, arguments, metadata, time_running, ...}
end
```
--------------------------------
### Specific Notification Event Subscription Example
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/types.md
Example of subscribing to a specific 'succeeded.maintenance_tasks' event to log task completion details.
```ruby
ActiveSupport::Notifications.subscribe "succeeded.maintenance_tasks" do |name, start, finish, id, payload|
TaskCompletionLog.create!(
task_name: payload[:task_name],
duration: payload[:time_running]
)
end
```
--------------------------------
### Error Context Subscription Example
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/types.md
Example of subscribing to errors using `Rails.error.subscribe` to access the error context payload.
```ruby
# Subscribing to errors
Rails.error.subscribe do |error, handled:, context:|
puts "Task: #{context[:task_name]}"
puts "Run: #{context[:run_id]}"
if context[:errored_element]
puts "Failed on: #{context[:errored_element]}"
end
end
```
--------------------------------
### Controller Usage Example
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/runs-page.md
Illustrates how to use RunsPage within a Rails controller to fetch and paginate run records.
```ruby
class TasksController < ApplicationController
def show
runs = MaintenanceTasks::Run
.where(task_name: params[:id])
.order(created_at: :desc)
@page = MaintenanceTasks::RunsPage.new(runs, params[:cursor])
@runs = @page.records
@has_next = !@page.last?
@next_cursor = @page.next_cursor if @has_next
end
end
```
--------------------------------
### Migrate Database
Source: https://github.com/shopify/maintenance_tasks/blob/main/README.md
Run this command after installing or reinstalling migrations to update the database schema.
```sh-session
bin/rails db:migrate
```
--------------------------------
### NullCollectionBuilder Override Example: collection
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/collection-builders.md
Example of overriding the `collection` method in a custom task to define how to retrieve a collection.
```ruby
class CustomTask < MaintenanceTasks::Task
def collection
User.all
end
end
```
--------------------------------
### on_start Method Implementation
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-job.md
Called when the iteration begins. It calculates the total count, updates the Run record, and triggers Task's start callbacks.
```ruby
def on_start -> void
```
--------------------------------
### Query Optimization Example
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/runs-page.md
Demonstrates query optimization techniques for forward-only pagination, including loading extra records to detect the next page and checking for its existence without loading the full result set.
```ruby
# Loads 21 records to check for next page
runs_after_cursor = runs.where("id < ?", cursor).limit(21)
# Returns first 20
records = runs_after_cursor.take(20)
# Checks if 21st exists without loading full result set
has_more = runs_after_cursor.length > 20
```
--------------------------------
### Example: Determine if Next Page Exists
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/runs-page.md
Demonstrates how to use the `last?` method to determine if a 'Next Page' link should be displayed.
```ruby
@page = MaintenanceTasks::RunsPage.new(runs, cursor: params[:cursor])
@show_next = !@page.last?
```
--------------------------------
### BatchCsvCollectionBuilder Example: Accessing BatchCsv Struct
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/collection-builders.md
Example showing how to obtain and access the fields of the BatchCsv struct returned by the `collection` method.
```ruby
batch_csv = builder.collection(task)
# batch_csv.csv = CSV object
```
--------------------------------
### Example of Triggering Callbacks on Transition
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/types.md
Shows how transitioning a run's status and persisting the transition triggers associated Task callbacks, such as `after_complete`.
```ruby
# When run transitions to :succeeded, calls task.run_callbacks(:complete)
run.status = :succeeded
run.persist_transition # Triggers Task's after_complete callbacks
```
--------------------------------
### Example Task Class within tasks_module
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/configuration.md
Demonstrates defining a task class within the configured `tasks_module` namespace and loading it by name.
```ruby
MaintenanceTasks.tasks_module = "Maintenance"
# Task files go in:
# app/tasks/maintenance/backfill_task.rb
class Maintenance::BackfillTask < MaintenanceTasks::Task
def collection
User.all
end
def process(user)
user.update!(state: "active")
end
end
# Load task by name:
task = MaintenanceTasks::Task.named("Maintenance::BackfillTask")
```
--------------------------------
### Example: Iterate Through Records
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/runs-page.md
Shows how to iterate through the records of a RunsPage object and display their task name and status.
```ruby
page.records.each do |run|
puts "#{run.task_name}: #{run.status}"
end
```
--------------------------------
### Example Custom TaskJob with Conditional Queuing
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/configuration.md
Illustrates a custom task job class with queueing logic that depends on the Rails environment.
```ruby
class CustomTaskJob < ActiveJob::Base
include MaintenanceTasks::TaskJobConcern
queue_as { Rails.env.production? ? :production : :default }
def on_error(error)
Sentry.capture_exception(error)
super
end
end
MaintenanceTasks.job = "CustomTaskJob"
```
--------------------------------
### Instantiate BatchCsv
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/types.md
Example of how to instantiate the BatchCsv struct with a CSV object and a batch size. This is typically used with the BatchCsvCollectionBuilder.
```ruby
batch_csv = MaintenanceTasks::BatchCsvCollectionBuilder::BatchCsv.new(
csv: CSV.new(content, headers: true),
batch_size: 100
)
```
--------------------------------
### Example: Custom Error Handling with `report_errors_as_handled = false`
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/configuration.md
Demonstrates how to subscribe to Rails errors and differentiate between task-handled and unexpected errors when `report_errors_as_handled` is set to false.
```ruby
# Report errors as unhandled for better error tracking
MaintenanceTasks.report_errors_as_handled = false
Rails.error.subscribe do |error, handled:, context:|
if context&.dig(:source) == "maintenance-tasks"
if handled
# Task handled this error with rescue_from
logger.info("Task recovered from: #{error}")
else
# Unexpected error
Sentry.capture_exception(error)
end
end
end
```
--------------------------------
### NullCollectionBuilder Override Example: count
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/collection-builders.md
Example of overriding the `count` method in a custom task to define how to count items in a collection.
```ruby
class CustomTask < MaintenanceTasks::Task
def count
User.count
end
end
```
--------------------------------
### Example of Catching Task NotFoundError
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/types.md
Demonstrates how to use a begin-rescue block to catch `MaintenanceTasks::Task::NotFoundError` when attempting to find a non-existent task.
```ruby
begin
MaintenanceTasks::Task.named("NonexistentTask")
rescue MaintenanceTasks::Task::NotFoundError => e
puts "Task not found: #{e.message}"
end
```
--------------------------------
### Check if Run has Started
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/run.md
Returns whether the run has begun its execution. Useful for determining if a task is still waiting to be picked up.
```ruby
if !run.started?
puts "Still waiting to be picked up"
end
```
--------------------------------
### Example Custom TaskJob with Queuing
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/configuration.md
Define a custom Active Job class for tasks, including custom queuing logic and error handling.
```ruby
class MyTaskJob < MaintenanceTasks::TaskJob
queue_as :maintenance_high_priority
end
MaintenanceTasks.job = "MyTaskJob"
```
--------------------------------
### Example: Using Complex Cursors with JSON Serialization
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/configuration.md
Illustrates defining a task that uses multiple cursor columns when `serialize_cursors_as_json` is enabled.
```ruby
MaintenanceTasks.serialize_cursors_as_json = true
# Now cursors can be complex structures
class Maintenance::CompositeKeyTask < MaintenanceTasks::Task
def cursor_columns
[:user_id, :created_at, :id] # Multiple columns
end
def process(record)
record.touch
end
end
```
--------------------------------
### Run.with_attached_csv
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/run.md
Eagerly loads the associated CSV file attachment if Active Storage is installed.
```APIDOC
## Run.with_attached_csv
### Description
Eagerly loads associated CSV file attachment if Active Storage is installed.
### Method
`Run.with_attached_csv`
### Parameters
None
### Response
Returns an `ActiveRecord::Relation` of `Run` objects with the CSV attachment loaded.
### Request Example
```ruby
runs = MaintenanceTasks::Run.with_attached_csv.limit(10)
```
```
--------------------------------
### Install Maintenance Task Migrations
Source: https://github.com/shopify/maintenance_tasks/blob/main/README.md
Use this command to copy the gem's migrations to your db/migrate folder, especially if previous migrations were deleted.
```sh-session
bin/rails maintenance_tasks:install:migrations
```
--------------------------------
### CsvCollectionBuilder Example: Processing CSV Content
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/collection-builders.md
Demonstrates how to retrieve and iterate over a CSV object obtained from the task's content.
```ruby
csv_content = "name,email\nAlice,alice@example.com\nBob,bob@example.com"
task.csv_content = csv_content
csv = task.collection_builder_strategy.collection(task)
csv.each do |row|
# row = {"name" => "Alice", "email" => "alice@example.com"}
end
```
--------------------------------
### Example: Conditional Logic for Stale Tasks
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Demonstrates using the `stale?` method to conditionally hide tasks from the main list and show them in an archive.
```ruby
if task_data.stale?
# Hide from main list, show in archive
end
```
--------------------------------
### Example of Valid and Invalid Status Transitions
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/types.md
Illustrates how to set run statuses and the expected outcome, including a valid transition and an invalid one that raises `ActiveRecord::RecordInvalid`.
```ruby
run.status = :running
run.status = :paused # Valid
run.save!
run.status = :cancelled # Invalid (paused → cancelled not allowed)
run.save! # Raises ActiveRecord::RecordInvalid
```
--------------------------------
### Example Task Using NoCollectionBuilder
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/collection-builders.md
Demonstrates how to use `no_collection` within a Maintenance::Task subclass to perform a single operation, such as clearing and warming the cache.
```ruby
class Maintenance::CacheWarmer < MaintenanceTasks::Task
no_collection
def process
Rails.cache.clear
Rails.cache.warm_up
end
end
```
--------------------------------
### Example CSV Data
Source: https://github.com/shopify/maintenance_tasks/blob/main/README.md
Sample data for a CSV file used with a CSV Maintenance Task. It includes headers and rows for importing posts.
```csv
title,content
My Title,Hello World!
```
--------------------------------
### Initialize TaskDataShow Instance
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Creates a TaskDataShow instance. Accepts task name, an optional runs cursor for pagination, and optional arguments.
```ruby
TaskDataShow.new(name, runs_cursor: nil, arguments: nil)
```
--------------------------------
### Get Task Instance from Run
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/run.md
Returns a Task instance with arguments assigned from the run. CSV content is not populated here and must be loaded separately.
```ruby
task = run.task
puts task.class.name
```
--------------------------------
### TaskDataShow.new
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Creates a TaskDataShow instance with the specified name, runs cursor, and arguments.
```APIDOC
## TaskDataShow.new
### Description
Creates a TaskDataShow instance.
### Method
Instance Method
### Signature
`TaskDataShow.new(name, runs_cursor: nil, arguments: nil)`
### Parameters
#### Arguments
- **name** (String) - Task class name
- **runs_cursor** (String, nil) - Cursor for run pagination
- **arguments** (Hash, nil) - Arguments to assign to Task
```
--------------------------------
### Run a Maintenance Task in Rails
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/cli.md
Install the gem and run maintenance tasks from your Rails application directory. The CLI automatically loads the Rails environment.
```bash
cd myapp
bundle exec maintenance_tasks perform Maintenance::MyTask
```
--------------------------------
### Example ERB for Task Show Page
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/endpoints.md
This ERB template displays task details, including its name, source code (if available), active runs, and run history. It utilizes instance variables like `@task` and its associated objects.
```erb
<%= @task.name %>
<% if @task.code %>
<%= @task.code %>
<% end %>
<% if @task.active_runs.any? %>
Active Runs
<% @task.active_runs.each do |run| %>
<% end %>
<% end %>
Run History
<% @task.runs_page.records.each do |run| %>
<% end %>
```
--------------------------------
### Get Available Tasks
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Returns a sorted list of all available Task metadata, including Run records. Sorting is based on category, recency, and name.
```ruby
TaskDataIndex.available_tasks -> Array
```
--------------------------------
### Customize Batch Size for Record Processing
Source: https://github.com/shopify/maintenance_tasks/blob/main/README.md
Modify the default batch size for fetching records from the database. This example sets the batch size to 1000.
```ruby
module Maintenance
class UpdatePostsTask < MaintenanceTasks::Task
# Fetch records in batches of 1000
collection_batch_size(1000)
def collection
Post.all
end
def process(post)
post.update!(content: "New content!")
end
end
end
```
--------------------------------
### Example of Catching Runner EnqueuingError
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/types.md
Shows how to catch `MaintenanceTasks::Runner::EnqueuingError` and access the associated `run` object to inspect details of the failed enqueue operation.
```ruby
begin
MaintenanceTasks::Runner.run(name: "MyTask")
rescue MaintenanceTasks::Runner::EnqueuingError => e
puts "Enqueue failed: #{e.message}"
puts "Run ID: #{e.run.id}"
end
```
--------------------------------
### Example ERB for Displaying Tasks by Category
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/endpoints.md
This ERB template iterates through available tasks, groups them by category, and displays each task's name and status. It requires the `@available_tasks` instance variable to be populated.
```erb
<% @available_tasks.group_by(&:category).each do |category, tasks| %>
<%= category %>
<% tasks.each do |task| %>
<%= link_to task.name, task_path(task) %>
<%= task.status %>
<% end %>
<% end %>
```
--------------------------------
### before_perform
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-job.md
Initializes the job execution context by loading the Run, preparing the Task, downloading CSV content if applicable, and transitioning the run to a running state.
```APIDOC
## Private Method: before_perform
### Description
Initializes job execution context.
### Signature
```ruby
def before_perform -> void
```
### Initializes:
- `@run` — First argument (Run record)
- `@task` — Run's Task instance
- Downloads CSV content if CSV task
- Transitions run to running
- Creates Ticker for progress updates
### Side effects:
- Transitions Run to running status
- Downloads CSV file from Active Storage if applicable
```
--------------------------------
### TaskDataShow#new
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Instantiates the Task class with assigned arguments, returning nil if the task file was deleted.
```APIDOC
## task_data.new
### Description
Instantiates the Task class with arguments.
### Method
Instance Method
### Signature
`task_data.new -> Task, nil`
### Returns
- Task instance with arguments assigned, if task exists
- nil if task file was deleted
### Example
```ruby
task = task_data.new
task.process # Execute task
```
```
--------------------------------
### Initialize Progress Tracker
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/progress.md
Creates a Progress tracker for a Run. Requires a Run object as input.
```ruby
class Progress
def initialize(run)
end
```
```ruby
Progress.new(run) -> Progress
```
```ruby
run = MaintenanceTasks::Run.find(123)
progress = MaintenanceTasks::Progress.new(run)
```
--------------------------------
### Batch Enumerator with Start Option Error
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/errors.md
This snippet shows an `ArgumentError` raised when a batch enumerator with unsupported `start` or `finish` options is used in the `collection` method.
```ruby
class BadTask < MaintenanceTasks::Task
def collection
Record.find_in_batches(start: 100) # start option not allowed
end
def process(batch)
end
end
MaintenanceTasks::Runner.run(name: "BadTask")
# => ArgumentError: BadTask#collection cannot support a batch enumerator...
```
--------------------------------
### Prepare TaskDataShow Instance
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Loads task data and ensures the task exists or has run history. Use this to prepare a TaskDataShow instance with optional run pagination and arguments.
```ruby
TaskDataShow.prepare(
"Maintenance::BackfillTask",
runs_cursor: "123"
)
```
--------------------------------
### Get Task Name
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Returns the task name. This method is aliased to `to_s`.
```ruby
task_data.name -> String
```
--------------------------------
### Get Task Name
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Returns the task name. This method is an alias for `to_s`.
```ruby
puts task_data.name # "Maintenance::BackfillTask"
```
--------------------------------
### Run Task from CLI
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/runner.md
Illustrates how to execute a maintenance task using the command-line interface, including specifying a CSV file and task arguments.
```bash
# bin/maintenance_tasks perform MyTask --csv=/path/to/file.csv --arguments=name:value
```
--------------------------------
### progress.max
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/progress.md
Gets the maximum expected items to process. This accounts for cases where the total count was underestimated.
```APIDOC
## progress.max
### Description
Maximum expected items to process.
### Method
`progress.max`
### Logic:
- If estimatable (has total and haven't exceeded it) → returns tick_total
- Otherwise → returns tick_count (current best estimate)
### Note:
Accounts for when tick_count exceeds tick_total (total was underestimated)
### Example:
```ruby
progress.max # 1000
# If 1200 processed but expected 1000:
progress.max # 1200
```
```
--------------------------------
### Get Pagination Cursor
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/runs-page.md
Retrieves the current pagination cursor, which is the ID marking the pagination position.
```ruby
page.cursor
```
--------------------------------
### Initialize RunsPage
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/runs-page.md
Creates a paginated run page with specified runs and a cursor for pagination.
```ruby
RunsPage.new(runs, cursor)
```
--------------------------------
### Progress.new
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/progress.md
Creates a Progress tracker for a Run. This is the primary way to instantiate the Progress class.
```APIDOC
## Progress.new
### Description
Creates a Progress tracker for a Run.
### Method
`Progress.new(run)`
### Parameters
#### Path Parameters
- **run** (Run) - Required - The Run to track progress for
### Request Example
```ruby
run = MaintenanceTasks::Run.find(123)
progress = MaintenanceTasks::Progress.new(run)
```
```
--------------------------------
### TaskDataShow.prepare
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Loads task data and ensures the task exists or has run history. It returns a TaskDataShow instance with active/completed runs preloaded.
```APIDOC
## TaskDataShow.prepare
### Description
Loads task data and ensures task exists (or has run history).
### Method
Class Method
### Signature
`TaskDataShow.prepare(name, runs_cursor: nil, arguments: nil) -> TaskDataShow`
### Parameters
#### Arguments
- **name** (String) - Required - Task class name
- **runs_cursor** (String) - Optional - Cursor for pagination of completed runs
- **arguments** (Hash) - Optional - Task arguments for instantiation
### Returns
TaskDataShow instance with active/completed runs preloaded
### Raises
`Task::NotFoundError` — if task has no runs and doesn't exist
### Example
```ruby
task_data = MaintenanceTasks::TaskDataShow.prepare(
"Maintenance::BackfillTask",
runs_cursor: "123"
)
```
```
--------------------------------
### Create Run
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/endpoints.md
Creates and enqueues a new task run.
```APIDOC
## Create Run
### Description
Creates and enqueues a new task run.
### Method
POST
### Endpoint
/maintenance_tasks/tasks/:task_id/runs
### Parameters
#### Path Parameters
- **task_id** (String) - Required - Task class name
#### Request Body
- **csv_file** (File) - Conditional - CSV file (required if task uses CSV)
- **task[param_name]** (Mixed) - Optional - Task argument values
**Content-Type:** multipart/form-data (for CSV file upload)
### Response
#### Success Response (302 Redirect)
- **Location** - Redirects to task show page after creating run.
#### Error Response (422 Unprocessable Entity)
- **Status:** 422 Unprocessable Entity
- **Template:** `maintenance_tasks/tasks/show.html.erb`
- **Variables:**
- `flash.now.alert` — Error message
- `@task` — TaskDataShow with validation errors
#### Error Response (302 Redirect - Value Too Long)
- **Location:** Redirects with error message if arguments exceed column limits.
#### Error Response (302 Redirect - Enqueuing Error)
- **Location:** Redirects with error message if job enqueueing fails.
```
--------------------------------
### Implement Task Callbacks: after_start
Source: https://github.com/shopify/maintenance_tasks/blob/main/README.md
Use the `after_start` callback to execute custom logic immediately after a task begins. Exceptions in this callback will be handled by the task's error handler and may stop the task.
```ruby
module Maintenance
class UpdatePostsTask < MaintenanceTasks::Task
after_start :notify
def notify
NotifyJob.perform_later(self.class.name)
end
# ...
end
end
```
--------------------------------
### Get Task Status
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Returns the status of the latest run (e.g., 'running', 'succeeded', 'errored'), or 'new' if no runs exist.
```ruby
task_data.status -> String
```
--------------------------------
### Get Related Run Record
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Returns the associated Run record (active or most recent completed), or nil if no runs exist.
```ruby
task_data.related_run -> Run, nil
```
--------------------------------
### Task Run Creation Logic
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/endpoints.md
This Ruby code demonstrates the logic for creating a new task run, including handling CSV files, task arguments, and optional metadata configuration.
```ruby
run = Runner.run(
name: task_id,
csv_file: params[:csv_file],
arguments: params[:task].permit!.to_h,
metadata: instance_exec(&MaintenanceTasks.metadata || -> {})
)
```
--------------------------------
### progress.value
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/progress.md
Gets the current progress value, which is the number of items processed. Returns nil if progress cannot be estimated and the run is still active.
```APIDOC
## progress.value
### Description
Current progress value (number of items processed).
### Method
`progress.value`
### Returns
- Integer (tick_count) if progress is estimatable OR run is stopped
- nil if progress cannot be estimated and run is still running
### Logic:
- Stopped runs always return a value
- Running runs return nil if total is unknown (shows indefinite progress)
### Example:
```ruby
progress.value # 250 out of 1000
progress.value # 500 (if run completed)
```
```
--------------------------------
### Instantiate Task with Arguments
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Instantiates the Task class with assigned arguments. Returns a Task instance if the task exists, otherwise returns nil if the task file was deleted.
```ruby
task = task_data.new
task.process # Execute task
```
--------------------------------
### before_perform Method Implementation
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-job.md
Initializes the job execution context before performing the job. This includes loading the Run, preparing the Task, and setting up the Ticker.
```ruby
def before_perform -> void
```
--------------------------------
### Run a Task with Arguments from Command Line
Source: https://github.com/shopify/maintenance_tasks/blob/main/README.md
Execute a maintenance task that accepts command-line arguments using the `--arguments` option. Arguments are provided as key-value pairs.
```sh
bundle exec maintenance_tasks perform Maintenance::ParamsTask \
--arguments post_ids:1,2,3 content:"Hello, World!"
```
--------------------------------
### Get Parameter Names
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Returns an array of strings representing the names of parameters the Task accepts. Returns an empty array if the Task is deleted.
```ruby
task_data.parameter_names # ["status", "country", "batch_size"]
```
--------------------------------
### Get Paginated Runs
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Retrieves paginated completed runs for the task. Returns up to 20 most recent runs and includes a cursor for the next page.
```ruby
task_data.runs_page -> RunsPage
```
--------------------------------
### complete
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/run.md
Marks the run as succeeded and sets the ended_at timestamp. It should be followed by `persist_transition`.
```APIDOC
## complete
### Description
Marks run as succeeded and sets ended_at timestamp.
### Method
`complete`
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
None
### Request Example
```ruby
run.complete
run.persist_transition
```
### Response
#### Success Response
- **void**
#### Response Example
None
```
--------------------------------
### Get Task Category
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Categorizes the task based on the status of its related run. Returns :active, :new, or :completed. Used for grouping tasks in the UI.
```ruby
task_data.category -> Symbol
```
--------------------------------
### CLI: list
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/README.md
Command-line interface command to list all available maintenance tasks.
```APIDOC
## CLI: list
### Description
Lists all available maintenance tasks that can be performed via the command line.
### Command
`bundle exec maintenance_tasks list`
```
--------------------------------
### Import Posts from CSV with Options
Source: https://github.com/shopify/maintenance_tasks/blob/main/README.md
This snippet demonstrates how to import posts from a CSV file using the `csv_collection` macro with options to skip comment lines and strip whitespace from fields.
```ruby
module Maintenance
class ImportPosts
csv_collection(skip_lines: /^#/, converters: ->(field) { field.strip })
def process(row)
Post.create!(title: row["title"], content: row["content"])
end
end
end
```
--------------------------------
### List Available Maintenance Tasks
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/endpoints.md
Use this GET request to retrieve a list of all available maintenance tasks, categorized by their status (active, new, completed).
```http
GET /maintenance_tasks
GET /maintenance_tasks/tasks
```
--------------------------------
### CSV File Preparation Logic
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/cli.md
The `csv_file` method prepares the CSV input for the runner. It handles stdin, file paths, and raises an error for non-existent files.
```ruby
def csv_file
return unless options.key?(:csv)
csv_option = options[:csv]
if csv_option == :stdin
{
io: StringIO.new($stdin.read),
filename: "stdin.csv",
content_type: "text/csv",
}
else
{
io: File.open(csv_option),
filename: File.basename(csv_option),
content_type: "text/csv",
}
end
rescue Errno::ENOENT
raise ArgumentError, "CSV file not found: #{csv_option}"
end
```
--------------------------------
### Get Completed Runs
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Returns finished task executions with statuses succeeded, errored, or cancelled. The value is cached after first access and serves as historical reference.
```ruby
task_data.completed_runs -> ActiveRecord::Relation
```
--------------------------------
### Handling Task::NotFoundError
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/errors.md
Demonstrates how to rescue and handle a Task::NotFoundError. This allows for graceful failure and alternative actions, such as displaying archived run history.
```ruby
begin
task = MaintenanceTasks::Task.named("MyTask")
rescue MaintenanceTasks::Task::NotFoundError => e
puts "Task not found: #{e.message}"
# May want to show archived run history instead
end
```
--------------------------------
### Get Next Page Cursor
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/runs-page.md
Returns the cursor for the next page, which is the ID of the last record on the current page. Raises an error if called when records is empty.
```ruby
page.next_cursor
```
--------------------------------
### Task Show
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/endpoints.md
Displays a specific task, its source code, parameters, and run history.
```APIDOC
## Task Show
### Description
Displays a specific task, its source code, parameters, and run history.
### Method
GET
### Endpoint
/maintenance_tasks/tasks/:id
### Parameters
#### Path Parameters
- **id** (String) - Required - Task class name (e.g., "Maintenance::BackfillTask")
#### Query Parameters
- **cursor** (String) - Optional - Pagination cursor for completed runs
- **{other}** (Mixed) - Optional - Task arguments as query parameters
### Response
#### Success Response (200 OK)
- **@task** (TaskDataShow) - An object containing task details.
- **name** (String) - Task class name
- **active_runs** (Array) - Array of currently running executions
- **runs_page** (RunsPage) - Object with pagination information for runs
- **code** (String) - Source file content (nil if deleted)
- **csv_task?** (Boolean) - Whether the task processes CSV
- **parameter_names** (Array) - Array of argument names
```
--------------------------------
### Get Masked Run Arguments
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/run.md
Returns run arguments with sensitive data filtered using Rails.application.config.filter_parameters and Task's masked_arguments. Returns nil if no arguments are present.
```ruby
safe_args = run.masked_arguments
# { api_key: '[FILTERED]' }
```
--------------------------------
### Executable Script Entry Point
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/cli.md
The `maintenance_tasks` executable script is the entry point for the CLI. It requires the CLI library and delegates execution to `MaintenanceTasks::CLI.start`.
```ruby
#!/usr/bin/env ruby
# exe/maintenance_tasks
require "maintenance_tasks/cli"
MaintenanceTasks::CLI.start(ARGV)
```
--------------------------------
### Error Reporting in Rails Application
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/README.md
Subscribe to Rails' error reporting system to capture exceptions originating from maintenance tasks. This example sends maintenance task errors to Sentry.
```ruby
Rails.error.subscribe do |error, handled:, context:|
if context[:source] == "maintenance-tasks"
Sentry.capture_exception(error)
end
end
```
--------------------------------
### Use Progress in Controllers
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/progress.md
Demonstrates how to instantiate and use the Progress class within a Rails controller to track task progress.
```ruby
class TasksController < ApplicationController
def show
@run = MaintenanceTasks::Run.find(params[:id])
@progress = MaintenanceTasks::Progress.new(@run)
end
end
```
--------------------------------
### Eager Load CSV Attachment
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/run.md
Eagerly loads the associated CSV file attachment for runs, provided Active Storage is installed. This is efficient for fetching runs that have associated CSV data.
```ruby
Run.with_attached_csv -> ActiveRecord::Relation
```
```ruby
runs = MaintenanceTasks::Run.with_attached_csv.limit(10)
```
--------------------------------
### List available maintenance tasks
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/cli.md
Display a list of all available maintenance tasks. The output is sorted alphabetically, with one task per line.
```bash
$ bundle exec maintenance_tasks list
Maintenance::ArchiveTask
Maintenance::BackfillTask
Maintenance::CleanupTask
```
--------------------------------
### Custom Rails Error Reporter Subscriber
Source: https://github.com/shopify/maintenance_tasks/blob/main/README.md
Example of a custom subscriber to Rails.error.report for integrating with an exception monitoring service like Bugsnag. This snippet demonstrates how to capture and report task-related errors.
```ruby
Bugsnag.notify(error) do |report|
report.add_tab(:maintenance_tasks, context)
end
```
--------------------------------
### Initialize TaskDataIndex
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Creates a TaskDataIndex instance with a task name and an optional related run record.
```ruby
TaskDataIndex.new(name, related_run = nil)
```
--------------------------------
### Optimize CSV Task Count Method
Source: https://github.com/shopify/maintenance_tasks/blob/main/README.md
An alternative implementation for the `#count` method in CSV tasks to avoid parsing the entire file. This example counts newlines to approximate the row count.
```ruby
def count
csv_content.count("\n") - 1
end
```
--------------------------------
### Subscribe to Maintenance Tasks Errors
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/errors.md
Example of subscribing to Rails' error reporter to handle errors originating from the maintenance-tasks source. This allows custom error logging or reporting, such as sending to Sentry.
```ruby
Rails.error.handle(source: "maintenance-tasks") do
MaintenanceTasks::Runner.run(name: "MyTask")
end
Rails.error.subscribe do |error, handled:, context:|
if context[:source] == "maintenance-tasks"
puts "Task error: #{context[:task_name]}"
puts "Error: #{error.message}"
Sentry.capture_exception(error)
end
end
```
--------------------------------
### Run a Task with Arguments from Ruby
Source: https://github.com/shopify/maintenance_tasks/blob/main/README.md
Execute a maintenance task that accepts arguments from Ruby using `MaintenanceTasks::Runner.run`. Pass arguments as a hash to the `arguments` option.
```ruby
MaintenanceTasks::Runner.run(
name: "Maintenance::ParamsTask",
arguments: { post_ids: "1,2,3" }
)
```
--------------------------------
### Define a Custom High-Priority Task Job
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-job.md
Example of defining a custom job that inherits from ActiveJob::Base and includes MaintenanceTasks::TaskJobConcern. It specifies a high-priority queue and custom error handling.
```ruby
class HighPriorityTaskJob < ActiveJob::Base
include MaintenanceTasks::TaskJobConcern
queue_as :maintenance_high_priority
def on_error(error)
Sentry.capture_exception(error)
super # Calls default error handling
end
end
MaintenanceTasks.job = "HighPriorityTaskJob"
```
--------------------------------
### CLI Option Parsing for CSV
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/cli.md
Demonstrates how the CSV option is parsed. It defaults to stdin if no value is provided, and accepts a file path or '-' for stdin.
```ruby
option :csv, lazy_default: :stdin, desc: "..."
```
--------------------------------
### CsvCollectionBuilder Class Initialization
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/collection-builders.md
Initializes the CsvCollectionBuilder, accepting CSV parsing options. Defaults to `{headers: true}`.
```ruby
class CsvCollectionBuilder
def initialize(**csv_options)
end
```
--------------------------------
### Get Active Runs
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/task-data.md
Returns currently running task executions, including statuses like enqueued, running, pausing, cancelling, paused, and interrupted. The value is cached after first access.
```ruby
task_data.active_runs -> ActiveRecord::Relation
```
--------------------------------
### Run a Basic Maintenance Task
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/runner.md
Creates a Run record and enqueues a Job for a specified task. Use this for simple task execution without additional parameters.
```ruby
task = MaintenanceTasks::Runner.run(name: "Maintenance::BackfillTask")
```
--------------------------------
### Show Specific Task Details
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/endpoints.md
Use this GET request to view the details of a specific maintenance task, including its source code, parameters, and run history. The task ID is the class name.
```http
GET /maintenance_tasks/tasks/:id
```
--------------------------------
### Get Current Progress Value
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/progress.md
Retrieves the current number of items processed. Returns an Integer if progress is estimatable or the run is stopped, otherwise nil if the run is still running and progress cannot be estimated.
```ruby
progress.value -> Integer, nil
```
```ruby
progress.value # 250 out of 1000
progress.value # 500 (if run completed)
```
--------------------------------
### Runner.run
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/api-reference/runner.md
Creates a Run record for a Task and enqueues the Job for execution. This method allows for basic task execution, tasks with arguments, CSV file processing, and custom metadata persistence.
```APIDOC
## Runner.run
### Description
Creates a Run record for a Task and enqueues the Job for execution. This method allows for basic task execution, tasks with arguments, CSV file processing, and custom metadata persistence.
### Method Signature
`Runner.run(name:, csv_file: nil, arguments: {}, run_model: Run, metadata: nil) { |run| ... } -> Task`
### Parameters
#### Path Parameters
* **name** (String) - Required - Task class name (e.g., "Maintenance::BackfillTask")
* **csv_file** (Hash, nil) - Optional - Attachable CSV file (see ActiveStorage::Attached::One#attach)
* **arguments** (Hash) - Optional - Task parameters to persist and pass to Task instance
* **run_model** (Class) - Optional - Run model class (for testing/custom implementations)
* **metadata** (Hash, nil) - Optional - Custom metadata to persist with the run
* **block** (Proc) - Optional - Optional block yielded with Run before enqueueing
### CSV File Structure
```ruby
{
io: File.open('path.csv'), # or StringIO
filename: 'data.csv',
content_type: 'text/csv'
}
```
### Returns
Task class (not instance)
### Raises
* `EnqueuingError` — if Job fails to enqueue
* `ActiveRecord::RecordInvalid` — if Run validation fails
* `ActiveRecord::ValueTooLong` — if argument values exceed column limits
### Examples
**Basic task:**
```ruby
task = MaintenanceTasks::Runner.run(name: "Maintenance::BackfillTask")
```
**With arguments:**
```ruby
task = MaintenanceTasks::Runner.run(
name: "Maintenance::UpdateUsersTask",
arguments: { status: "active", country: "US" }
)
```
**CSV task:**
```ruby
csv_file = {
io: File.open('users.csv'),
filename: 'users.csv',
content_type: 'text/csv'
}
task = MaintenanceTasks::Runner.run(
name: "Maintenance::ImportUsersTask",
csv_file: csv_file
)
```
**With metadata and block:**
```ruby
task = MaintenanceTasks::Runner.run(
name: "Maintenance::CleanupTask",
metadata: { triggered_by: "admin_user", reason: "manual_cleanup" }
) do |run|
# Inspect/modify run before enqueueing
puts "Run ID: #{run.id}"
end
```
**From CLI:**
```ruby
# bin/maintenance_tasks perform MyTask --csv=/path/to/file.csv --arguments=name:value
```
```
--------------------------------
### CLI: perform
Source: https://github.com/shopify/maintenance_tasks/blob/main/_autodocs/README.md
Command-line interface command to perform a specific maintenance task.
```APIDOC
## CLI: perform
### Description
Executes a specified maintenance task directly from the command line.
### Command
`bundle exec maintenance_tasks perform TaskName [--csv data.csv] [--args key=value]`
### Parameters
- **TaskName** (string) - Required - The name of the task to perform.
- **--csv** (string) - Optional - Path to a CSV file to process.
- **--args** (string) - Optional - Arguments to pass to the task, formatted as key=value pairs.
```