Расширение ActiveJob с помощью очереди DelayedJob в Rails 5.x - PullRequest
0 голосов
/ 01 марта 2020

Кажется невозможным получить доступ к объекту delayed_job из activeJob.

До сих пор я работал над этим, добавив контекст в качестве дополнительного аргумента (и удалив его по вызову), поэтому я могу добавить любую дополнительную информацию, которая мне нужна (например, многопользовательская аренда). Это закодировано в столбце handler как любые другие аргументы.

Я хочу найти дубликаты, и при использовании этого подхода есть некоторые проблемы. Поэтому я хотел бы определить столбец дополнительного идентификатора задания j_id, который будет использоваться для поиска дубликатов.

Поскольку я не могу получить доступ к delayed_job, я не могу найти способ его заполнить.

Это то, что я сделал до сих пор:

# already added column j_id to delayed_job table in migration file
class ApplicationJob < ActiveJob::Base
 before_enqueue :add_context

  def add_context
    # How can I set the j_id from here?
  end

1 Ответ

0 голосов
/ 02 марта 2020

ActiveJob в Rails похож на ActiveRecord в том, что они оба предоставляют стабильный API для бэкэнда (в случае с DB в AR и для AJ в виде очереди). DelayedJob - это только один из бэкэндов AJ, так же как MySQL или Postgresql являются бэкэндами для AR.

Если вы копаетесь в коде DelayedJob (и вы используете ActiveRecord в качестве бэкэнда для DelayedJob через гем delayed_job_active_record), вы обнаружит, что Delayed :: Job - это просто еще один подкласс ActiveRecord :: Base, как и любая из ваших моделей.

Это означает, что у вас есть доступ ко всем объектам DelayedJob через Класс Delayed :: Job, со всеми методами поиска и проверки, которые вы можете ожидать от ActiveRecord.

#<Delayed::Backend::ActiveRecord::Job:0x00007f00889c3210
 id: 1,
 priority: 0,
 attempts: 0,
 handler:
  "--- !ruby/object:ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper\n" +
  "job_data:\n" +
  "  job_class: ApplicationJob\n" +
  "  job_id: 5f7539a3-120a-45b4-a6d7-12ec8c6cad3d\n" +
  "  provider_job_id: \n" +
  "  queue_name: default\n" +
  "  priority: \n" +
  "  arguments: []\n" +
  "  executions: 0\n" +
  "  exception_executions: {}\n" +
  "  locale: en\n" +
  "  timezone: UTC\n" +
  "  enqueued_at: '2020-03-02T05:38:22Z'\n",
 last_error: nil,
 run_at: Mon, 02 Mar 2020 05:38:22 UTC +00:00,
 locked_at: nil,
 failed_at: nil,
 locked_by: nil,
 queue: "default",
 created_at: Mon, 02 Mar 2020 05:38:22 UTC +00:00,
 updated_at: Mon, 02 Mar 2020 05:38:22 UTC +00:00>

Этот класс поддерживается таблицей с именем delayed_jobs, как вы могли ожидать от любого класса AR, поэтому Вы можете создавать миграции, которые добавляют или изменяют столбцы в этой таблице (добавьте j_id):

rails g migration AddJIdToDelayedJobs j:string

Чтобы добавить проверку, вы можете создать config/initializers/delayed_job.rb и monkey patch класс.

module Delayed
  class Job
     validates :j_id, uniqueness: true                                                                                                                                  
  end                                                                                                                                       
end

Осталось только добавить данные в столбец j_id при постановке в очередь. Таким образом, вы можете добавить любую информацию, которая сделает ваши работы уникальными, это может быть идентификатор какой-либо другой модели, параметры работы или все, что вам нужно. DelayedJob предоставляет классное решение plugin , поэтому мы можем использовать его для подключения к жизненному циклу заданий и добавления информации в j_id, когда задание ставится в очередь. Вернувшись в config/initializers/delayed_job.rb, давайте добавим новый класс плагина:

module Delayed
  class UniqueJobsPlugin < Plugin
    callbacks do |lifecycle|
      lifecycle.before(:enqueue) do |job|
        job.j_id = job #.anything inside the job, remember .handler is in YAML
      end
    end
  end
end
Delayed::Worker.plugins << Delayed::UniqueJobsPlugin

Чтобы получить любую информацию в атрибуте обработчика YAML, вы можете сделать handler_attributes = YAML.load(job.handler)

Теперь, если j_id не уникальное задание завершится ошибкой с обычной ошибкой уникальности AR, которую вы можете обработать в контроллере, который поставил в очередь задание, или откуда вы ставите задание в очередь.

...