저장시 BackgroundJob이 여러 번 트리거 됨 (Rails 5, Sidekiq)

Nov 24 2020

Cloundinary백그라운드 작업 을 통해 PDF 파일 업로드를 처리하고 있습니다 . after_save콜백 에서 큐에 넣습니다 . 딜레 나는 하나의 업데이트에 대해 내 백그라운드 작업이 여러 번 트리거된다는 것입니다. 이 결함에 대응 around_perform하기 위해를 사용하여 작업이 한 번만 트리거되도록 하는 메서드를 구현하려고했습니다 . 그러나 실제로 작동하지 않았습니다. 원치 않는 일을 처리하는 방법을 아는 사람이 있는지 궁금합니다.

내 코드는 다음과 같습니다.

after_save콜백

콜백은 내 모델 송장 및 견적 모두에 배치됩니다.

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

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

이 부분에서는라는 변수에 인스턴스를 넣습니다 element.

아이디어는 UploadPdfJob작업이 두 번 이상 대기열에 추가되는 경우였습니다. PDF는 한 번만 업로드됩니다. 첫 번째 작업은로 설정 uploaded되고 true두 번째 작업은 확인 후 종료됩니다.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검색된 인스턴스에 의존하지 않는 라는 변수 사용

    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

답변

DaviGo Nov 25 2020 at 21:48

나는 소매를 감아 야했지만 마침내 마지막 단어를 얻었다. 나는으로 디버깅 binding.pry하고 문제의 근원을 찾아 내 작업을 트리거하는 코드의 모든 부분을 찾아 업데이트했습니다.

또한 원치 않는 트리거를 방지하기 위해 저장된 매개 변수가 작업을 설정해야하는 사용자 지정 가드 콜백을 추가했습니다.

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