From 6495eb3cd3074936776ebad636be8f6862704e48 Mon Sep 17 00:00:00 2001 From: JP Camara <48120+jpcamara@users.noreply.github.com> Date: Wed, 7 Feb 2024 22:06:21 -0500 Subject: [PATCH] Allow batch jobs to be instances * This means we can store the arguments and settings by letting the user do `BatchJob.new(arguments).set(options)` * Yield the batch in `enqueue` in case someone needs info from it * When you serialize then deserialize an activejob instance, the arguments are in the serialized_arguments field and can only be transferred over by the private method `deserialize_arguments_if_needed`. This is pretty janky, so there is probably something i'm missing * `perform_all_later` let's us do a perform_later even with instance, which does not seem to be possible on the instances themselves --- app/models/solid_queue/job_batch.rb | 38 +++++++++++-------- ...31013203_create_solid_queue_batch_table.rb | 4 +- test/dummy/db/schema.rb | 4 +- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/app/models/solid_queue/job_batch.rb b/app/models/solid_queue/job_batch.rb index fb281fbb..96e449b3 100644 --- a/app/models/solid_queue/job_batch.rb +++ b/app/models/solid_queue/job_batch.rb @@ -5,6 +5,9 @@ class JobBatch < Record belongs_to :job, foreign_key: :job_id, optional: true has_many :jobs, foreign_key: :batch_id + serialize :on_finish_active_job, coder: JSON + serialize :on_success_active_job, coder: JSON + scope :incomplete, -> { where(finished_at: nil).where("changed_at IS NOT NULL OR last_changed_at < ?", 1.hour.ago) } @@ -21,7 +24,7 @@ def enqueue(attributes = {}) transaction do job_batch = create!(batch_attributes(attributes)) ActiveSupport::IsolatedExecutionState[:current_batch_id] = job_batch.id - yield + yield job_batch end job_batch @@ -40,20 +43,22 @@ def dispatch_finished_batches private def batch_attributes(attributes) - attributes = case attributes - in { on_finish: on_finish_klass } - attributes.merge( - job_class: on_finish_klass, - completion_type: "success" - ) - in { on_success: on_success_klass } - attributes.merge( - job_class: on_success_klass, - completion_type: "success" - ) + on_finish_klass = attributes.delete(:on_finish) + on_success_klass = attributes.delete(:on_success) + + if on_finish_klass.present? + attributes[:on_finish_active_job] = as_active_job(on_finish_klass).serialize + end + + if on_success_klass.present? + attributes[:on_success_active_job] = as_active_job(on_success_klass).serialize end - attributes.except(:on_finish, :on_success) + attributes + end + + def as_active_job(active_job_klass) + active_job_klass.is_a?(ActiveJob::Base) ? active_job_klass : active_job_klass.new end end @@ -74,9 +79,10 @@ def finish attrs = {} - if job_class.present? - job_klass = job_class.constantize - active_job = job_klass.perform_later(self) + if on_finish_active_job.present? + active_job = ActiveJob::Base.deserialize(on_finish_active_job) + active_job.send(:deserialize_arguments_if_needed) + ActiveJob.perform_all_later([active_job]) attrs[:job] = Job.find_by(active_job_id: active_job.job_id) end diff --git a/db/migrate/20240131013203_create_solid_queue_batch_table.rb b/db/migrate/20240131013203_create_solid_queue_batch_table.rb index bf8d97ce..26540b9c 100644 --- a/db/migrate/20240131013203_create_solid_queue_batch_table.rb +++ b/db/migrate/20240131013203_create_solid_queue_batch_table.rb @@ -2,8 +2,8 @@ class CreateSolidQueueBatchTable < ActiveRecord::Migration[7.1] def change create_table :solid_queue_job_batches do |t| t.references :job, index: { unique: true } - t.string :job_class - t.string :completion_type + t.string :on_finish_active_job + t.string :on_success_active_job t.datetime :finished_at t.datetime :changed_at t.datetime :last_changed_at diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index bc919613..71a32103 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -48,8 +48,8 @@ create_table "solid_queue_job_batches", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.bigint "job_id" - t.string "job_class" - t.string "completion_type" + t.string "on_finish_active_job" + t.string "on_success_active_job" t.datetime "finished_at" t.datetime "changed_at" t.datetime "last_changed_at"