Ruby on rails 如何使作业幂等,每月运行1次(Rails 5)?
我需要根据EST/EDT时区每月生成一次发票(客户遍布全国,但在这个行业中,计费发生在同一时区) 我正在创建一个Ruby on rails 如何使作业幂等,每月运行1次(Rails 5)?,ruby-on-rails,ruby,datetime,ruby-on-rails-5,delayed-job,Ruby On Rails,Ruby,Datetime,Ruby On Rails 5,Delayed Job,我需要根据EST/EDT时区每月生成一次发票(客户遍布全国,但在这个行业中,计费发生在同一时区) 我正在创建一个GenerateInvoicesJob,但我很难推理出一个100%完美的生成发票的方法,这样就不会有任何可能的重复/混淆: 每月仅生成一次发票 让作业每天运行 使作业幂等 最后一点对我来说是很难的,我如何确保EST/DST没有错误,一个小时没有通过 这是我的钟 every(1.day, 'GenerateInvoicesJob', tz: 'America/New_York', a
GenerateInvoicesJob
,但我很难推理出一个100%完美的生成发票的方法,这样就不会有任何可能的重复/混淆:
- 每月仅生成一次发票
- 让作业每天运行
- 使作业幂等
every(1.day, 'GenerateInvoicesJob', tz: 'America/New_York', at: '04:00') do
Delayed::Job.enqueue GenerateInvoicesJob.new, queue: 'high'
end
以下是我工作的重点:
Unit.where(enabled: true)
.joins(:user)
.where('last_invoice_generated_at <= ?', Time.now.utc.end_of_month)
.each do |unit|
ActiveRecord::Base.transaction do
unit.update_attributes(
last_invoice_generated_at: Time.now.utc
)
invoice = Invoice.create!(
...
)
line_item = LineItem.create!(
...
)
end
Unit.where(启用:true)
.joins(:用户)
.where('last_invoice_generated_at我会在worker中执行以下操作:
# `beginning_of_month` because we want to load units that haven't
# been billed this month
units_to_bill = Unit.where(enabled: true)
.where('last_invoice_generated_at < ?', Time.current.beginning_of_month)
# `find_each` because it needs less memory
units_to_bill.find_each do |unit|
# Beginn a transaction to ensure all or nothing is updated
Unit.transaction do
# reload the unit, because it might have been updated by another
# task in the meantime
unit.reload
# lock the current unit for updates
unit.lock!
# check if the condition is still true
if unit.last_invoice_generated_at < 1.month.ago
# generate invoices
# invoice = Invoice.create!(
# line_item = LineItem.create!(
# last step update unit
unit.update_attributes(
last_invoice_generated_at: Time.current
)
end
end
end
##'月初',因为我们要加载尚未加载的单元
#这个月已经结账了
单位到账单=单位,其中(启用:真)
.where('最后一张发票生成时间<?',时间.当前.月初)
#'查找每个',因为它需要更少的内存
单位到账单。找到每个做的单位|
#开始一个事务以确保全部或全部更新
事务处理
#重新加载该单元,因为它可能已被另一个更新
#同时完成任务
重新加载
#锁定当前设备进行更新
单位,锁!
#检查条件是否仍然正确
如果上次发票生成时间小于1个月
#生成发票
#发票=发票。创建(
#line\u item=LineItem.create(
#最后一步更新单元
unit.update\u属性(
上次生成的发票日期:Time.current
)
结束
结束
结束
Hmm,Time.current与Time.now.utc有何不同(如果我的服务器设置为utc,我刚才添加了“utc”只是为了保存,即使它不是必需的)另外,事务完成是否会自动解锁记录?我从来没有使用过这种方法,看起来很棒。Time.current
是Time.now
。是的,事务结束时也会释放单元上的锁。啊,很有趣。Time.current也是如此(Rails设置为UTC
)仍然确认有效期+/-1小时DST?不,这并不重要,但对于您的员工来说并不重要,因为员工只关心不生成重复发票。但外部时钟有责任按时启动员工,而且确实如此(从上面的代码来看)。