I need to generate invoices once per month, according to the EST/EDT timezone (the clients are throughout the country but in this industry billing happens at the same timezone).
I'm creating a GenerateInvoicesJob
but I'm having trouble reasoning about a 100% perfect way to generate invoices so that there isn't any possible duplicate/confusion with regards to:
- Generate invoices only once per month
- Let the job run every day
- Make the job idempotent
Then the final point which is the hard one for me, how do I ensure that there are no bugs with EST/DST and 1 hour slipping through.
Here is my clock.rb:
every(1.day, 'GenerateInvoicesJob', tz: 'America/New_York', at: '04:00') do
Delayed::Job.enqueue GenerateInvoicesJob.new, queue: 'high'
end
And here's the top of my job:
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
I realize the direct conditional logic might be wrong, so that's not entirely my question... my main addition to that question is whats the best way overall to do this so I can make sure that all times in EST are 100% accounted for, including weird off-by-1-hour bugs, etc. This job is super important so I'm hesitant on a way to make it perfect.
On top of that I"m not sure whether I should store UTC in the database.... normally I know you always are supposed to store UTC, but I know UTC doesnt have DST so I'm afraid if I store it like that, the job could run one time and invoices would be not run properly