Repository: Shopify/maintenance_tasks (Ruby)

Issue:
Expose `Run#metadata` to `Task` subclasses
Similar to https://github.com/Shopify/maintenance_tasks/pull/1112, would be interesting to supply the `run.metadata` hash to the `Task` instance when it's executed. 

A use case we have for this is to identify the user that enqueued the run for audit/logging purposes. We already have this on `MaintenanceTasks.metadata`:

```ruby
# config/initializers/maintenance_tasks.rb

MaintenanceTasks.parent_controller = "Dev::ApplicationController"

MaintenanceTasks.metadata = ->() do
  { user_id: current_user.id }
end
```

But this object isn't available inside the task

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

module Maintenance
  class HelloTask < MaintenanceTasks::Task
    no_collection

    def process
      user = User.find(metadata.fetch("user_id")) # <-- undefined local variable or method 'metadata' for an instance of Maintenance::HelloTask
      puts "User #{user.email} is invoking the task"
    end
  end
end
```

I can try to submit a patch for this if it's welcome



Discussion:
The metadata is on the `run` only because it is what we use to audit and log the user that triggers that task. Any reason why you can't do the auditing in the run and need to do in the task?
We have some specific tasks that update/insert db records and we would like to associate those changes with the `Admin` record for the user that enqueued the task. One way we did this was to add an `attribute` with the admin's email, but if the task have access to the `metadata` we can just have a `def current_admin` method on the task class without relying on user input for this.



Patch:
diff --git a/app/models/maintenance_tasks/run.rb b/app/models/maintenance_tasks/run.rb
index c1dc5e47f..0784396ee 100644
--- a/app/models/maintenance_tasks/run.rb
+++ b/app/models/maintenance_tasks/run.rb
@@ -422,6 +422,8 @@ def task
         if task.attribute_names.any? && arguments.present?
           task.assign_attributes(arguments)
         end
+
+        task.metadata = metadata
         task
       rescue ActiveModel::UnknownAttributeError
         task
diff --git a/app/models/maintenance_tasks/task.rb b/app/models/maintenance_tasks/task.rb
index 36bfa2239..1cf328fb6 100644
--- a/app/models/maintenance_tasks/task.rb
+++ b/app/models/maintenance_tasks/task.rb
@@ -35,6 +35,8 @@ class NotFoundError < NameError; end
 
     define_callbacks :start, :complete, :error, :cancel, :pause, :interrupt
 
+    attr_accessor :metadata
+
     class << self
       # Finds a Task with the given name.
       #


Test patch:
diff --git a/test/models/maintenance_tasks/run_test.rb b/test/models/maintenance_tasks/run_test.rb
index 7490ade95..210b90b0c 100644
--- a/test/models/maintenance_tasks/run_test.rb
+++ b/test/models/maintenance_tasks/run_test.rb
@@ -631,6 +631,11 @@ class RunTest < ActiveSupport::TestCase
       assert_kind_of Maintenance::UpdatePostsTask, run.task
     end
 
+    test "#task sets the metadata on the Task" do
+      run = Run.new(task_name: "Maintenance::TestTask", metadata: { foo: "bar" })
+      assert_equal({ "foo" => "bar" }, run.task.metadata)
+    end
+
     test "#validate_task_arguments instantiates Task and assigns arguments if Task has parameters" do
       run = Run.new(
         task_name: "Maintenance::ParamsTask",