ruby-on-rails - BackgroundJob 在保存时触发多次(Rails 5,Sidekiq)
问题描述
我正在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
解决方案
我不得不卷起袖子,但我终于说了算。我进行了调试binding.pry
,找到了问题的根源,并找出并更新了触发我工作的代码的每一部分。
此外,为了进一步防止任何不必要的触发,我添加了一个自定义的保护回调,说明保存的哪些参数应该让 Job 启动。
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
推荐阅读
- http - 如何在 Go 中的测试中模拟 http 请求的 504 超时错误?
- reactjs - 从 JSON 对象 data.results 设置状态时反应 16 出错
- javascript - 如何在 Node.js 的 Selenium 脚本中访问控制台中的变量?
- javascript - How to push object by following its structure to array of objects
- asp.net-web-api - Swagger 在路由调整后显示相同方法的两个端点
- sql-server - 为 TFS 安装 SQL 分析服务的原因是什么?
- java - HTML 选项卡不会重定向到上一个选定的选项卡,而是重定向到第一个选项卡
- android - 浮动操作按钮 + 协调器 Layot + 位置和放置问题
- encryption - 如何区分实时流量中的加密和压缩
- reactjs - 使用 MathML 标签反应 16 个 HTML 属性