BackgroundJob在保存时触发了多次(Rails 5,Sidekiq) [英] BackgroundJob triggered multiple times on save ( Rails 5, Sidekiq)

查看:84
本文介绍了BackgroundJob在保存时触发了多次(Rails 5,Sidekiq)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过后台作业处理在Cloundinary上的PDF文件的上载.我从after_save回调中将它们加入队列.问题在于,一次更新会使我的后台作业被触发多次.为了解决此缺陷,我尝试使用around_perform实现一种方法,以确保仅一次触发我的作业.但是它实际上没有用.我想知道你们中的任何人是否知道如何处理那些对工作的不必要的呼叫

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

这是我的代码

我的after_save回调

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

结束

我的工作UploadPDFJob

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

我的around_perform

My around_perform

在这一部分中,我将实例放在名为element的变量中.

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

这个想法是,如果UploadPdfJob作业被多次排队. PDF仅上传一次.第一个作业将uploaded设置为true,然后在检查done

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

此外,由于我不想在更新时触发回调,因此我尝试了这种方式.使用名为start的变量,该变量不依赖于我检索到的实例

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

推荐答案

我不得不袖手旁观,但是我终于有了硬道理.我用binding.pry进行了调试,找到了问题的根本原因,找出并更新了触发我的工作的所有代码.

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

这篇关于BackgroundJob在保存时触发了多次(Rails 5,Sidekiq)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆