Выполнение кода при неудачном завершении задачи

Рейтинг: 0Ответов: 1Опубликовано: 04.07.2023

Есть задача, приложение, которое принимает POST запросом json строку и перенаправляет его по другие адресам. Для решения данной задачи решил использловать гем delayed_job. Получаю из запроса строку, из базы список адресов и для каждого адреса создаю следующую задачу:

class JsonJob < ApplicationJob
  require 'httparty'

  def perform(destination_url, data_json)
 
    attempts = 5
    response_code = nil
    while attempts > 0 && response_code != 200
      # Выполнение запроса
      response = HTTParty.post(destination_url, body: data_json.to_json, headers: { 'Content-Type' => 'application/json' })
      response_code = response.code
    
      # Уменьшение количества попыток
      attempts -= 1

      # Если ответ не 200, ждем некоторое время перед повторной попыткой
      sleep(5) if response_code != 200
    end

    if response_code != 200
      raise StandardError, "Ошибка: попытки исчерпаны и ответ не 200"
    end
  end
end

На каждый адрес в базе успешно создается запись. Согласно настройкам в файле delayed_job_config, максимально количество попыток выполнения данной задачи 5. Мне нужно, чтобы после этих неудачных попыток, когда не получилось отправить строку получателям, было сформировано сообщение об ошибке, но не могу разобраться куда прописать данный код, и как вообще отловить что все попытки закончились.

Условно, могу получить значение переменной Delayed::Worker.max_attempts, но вот как получить значение текущей попытки я найти не могу.

Или может существует какой-то другой способ?

Ответы

▲ 0

Библиотека DelayedJob использует таблицу delayed_jobs, которая выглядит следующим образом:

create_table :delayed_jobs, :force => true do |table|
  table.integer  :priority, :default => 0      # Allows some jobs to jump to the front of the queue
  table.integer  :attempts, :default => 0      # Provides for retries, but still fail eventually.
  table.text     :handler                      # YAML-encoded string of the object that will do work
  table.text     :last_error                   # reason for last failure (See Note below)
  table.datetime :run_at                       # When to run. Could be Time.zone.now for immediately, or sometime in the future.
  table.datetime :locked_at                    # Set when a client is working on this object
  table.datetime :failed_at                    # Set when all retries have failed (actually, by default, the record is deleted instead)
  table.string   :locked_by                    # Who is working on this object (if locked)
  table.string   :queue                        # The name of the queue this job is in
  table.timestamps
end

Вы можете использовать поле attempts из этой таблицы.

Также советую взглянуть на коллбэки джоба:

class ParanoidNewsletterJob < NewsletterJob
  def enqueue(job)
    record_stat 'newsletter_job/enqueue'
  end

  def perform
    emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
  end

  def before(job)
    record_stat 'newsletter_job/start'
  end

  def after(job)
    record_stat 'newsletter_job/after'
  end

  def success(job)
    record_stat 'newsletter_job/success'
  end

  def error(job, exception)
    Airbrake.notify(exception)
  end

  def failure(job)
    page_sysadmin_in_the_middle_of_the_night
  end
end

Вас должен заинтересовать метод failure.

https://github.com/collectiveidea/delayed_job#gory-details