BackgroundJob triggered multiple times on save ( Rails 5, Sidekiq)

血红的双手。 提交于 2021-02-11 12:55:49

问题


I am handling the upload of PDFs' files on Cloundinary through a background jobs. I enqueue them from an after_save callback. The dilemna is that for one update my background job get triggered multiples times. To counter this flaw, I tried to implement a method using around_perform, to ensure that my job would be triggered only one time. But it actually did not work. I was wondering if any of you know how to handle those unwanted calls to the job

Here is my code

My after_save callback

The callback is placed on both my model Invoice and Quote.

Class Invoice
 after_save :upload_pdf

 def upload_pdf
   UploadPdfJob.perform_later(self.id,'invoice')

   new_notif_paid = Notification.create(user: self.user,
     category: "PDF",
     content: "Your PDF #{self.reference}
            is available ",
     element: "invoice",
     element_id: self.id)
 end

end

My Job UploadPDFJob

def perform(id, type)
   create_pdf_copy(id, type)
end


def create_pdf_copy(id, type)

  wicked = WickedPdf.new

  value = type == 'invoice'? Invoice.find(id) : Quote.find(id)
  template_path = type == 'invoice'? 'invoices/show': 'quotes/show.html.erb'
  file_type = type == 'invoice'? 'facture': 'devis'


  pdf_html = ApplicationController.render(
    locals: {
      current_user: value.user,
    },
    assigns: {
      "#{type}": value,
      format: 'pdf'
    },
    template: template_path,
    layout: 'pdf'
  )

  pdf_file = wicked.pdf_from_string(pdf_html,
    page_size: 'A4',
    orientation: "portrait",
    lowquality: true,
    zoom: 0.9,
    dpi: 75
  )

  tempfile = Tempfile.new("#{file_type}-#{value.id}.pdf")

  File.open(tempfile.path, 'wb') do |file|
    file << pdf_file
  end

  tempfile.close


  unless pdf_file.blank?
    value.photo.attach(io: File.open(tempfile.path), filename: "#{file_type}-#{value.id}.pdf")
  end
end

My around_perform

In this part, I put my instance in a variable named element.

The idea was that, if the UploadPdfJob job is enqueued more than once. The PDF will only be uploaded once. The first job will set uploaded to true, then the second job will exit after checking done

  around_perform do |job, block|
    id = job.arguments.first
    element = job.arguments.last == 'invoice'? Invoice.find(id) : Quote.find(id)
    element.with_lock do
      return if element.uploaded
      if block.call
        element.update(uploaded: true)
      else
        retry_job
      end
  end

Also, as I did not want to trigger the callback on the update, I tried this way. Using a variable called start, that does not rely on my retrieved instance

    around_perform do |job, block|
      id = job.arguments.first
      element = job.arguments.last == 'invoice'? Invoice.find(id) : Quote.find(id)
      start = false
      element.with_lock do
        return if start == true
        if block.call
          start = true
        else
          retry_job
        end
      end
    end

回答1:


I had to roll up my sleeves, but I finally got the last word. I debugged with binding.pry,got to the very root of the problem and find out and updated every part of codes that were triggering my Job.

Also to further prevent any unwanted triggering, I added a customed guard callback stating which parameters saved should set the Job in motion.

Class Invoice

      after_save :upload_pdf, if: :should_upload?

      def should_upload?
        attributes = self.saved_changes
        %i[title client_id creation_date].any? {|val| attributes.key? val}
      end
    end


来源:https://stackoverflow.com/questions/64994252/backgroundjob-triggered-multiple-times-on-save-rails-5-sidekiq

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!