Ruby on rails 如何使作业幂等,每月运行1次(Rails 5)?

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

我需要根据EST/EDT时区每月生成一次发票(客户遍布全国,但在这个行业中,计费发生在同一时区)

我正在创建一个
GenerateInvoicesJob
,但我很难推理出一个100%完美的生成发票的方法,这样就不会有任何可能的重复/混淆:

  • 每月仅生成一次发票
  • 让作业每天运行
  • 使作业幂等
最后一点对我来说是很难的,我如何确保EST/DST没有错误,一个小时没有通过

这是我的钟

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?不,这并不重要,但对于您的员工来说并不重要,因为员工只关心不生成重复发票。但外部时钟有责任按时启动员工,而且确实如此(从上面的代码来看)。