● Generate the user's invoice ● Charge them ● Email them ● Place account holds on delinquent users ● Generate reports for internal finance teams ● Perform other relevant actions Our end-of-month pipeline
class MonthClose def perform generate_invoice_items # expensive amount = generate_invoice # expensive success = charge_balance(amount) # external dependencies email_user(amount) # external dependencies handle_failed_charge unless success # complicated and messy end end There's a lot to do
# app/workers/expensive_job_worker.rb class ExpensiveJobWorker include Sidekiq::Worker sidekiq_options(queue: :high) def perform(args) ExpensiveJob.new(args).expensive_method end end # app/lib/expensive_job.rb class ExpensiveJob def initialize(args) @args = args end def expensive_method end end
# Run it in the background every day # whenever gem => https://github.com/javan/whenever every :day do runner "ExpensiveJobWorker.perform_async(args)" end
class MonthCloseWorker def perform generate_invoice_items amount = generate_invoice charge_balance(amount) email_user(amount) handle_failed_charge end end We can do better
class MonthCloseWorker def perform generate_invoice_items amount = generate_invoice PaymentWorker.perform_async(amount) EmailWorker.perform_async(amount) end end Applying it to our use case class PaymentWorker def perform(amount) success = charge_user(amount) HandleFailedChargeWorker.perform_async unless success end end class HandleFailedChargeWorker def perform handle_failed_charge end end class EmailWorker def perform(amount) email_user(amount) end end
Before ● ~30 minutes per user (on average) ● 1-2 days for entire month close process After ● <10 minutes per user ● <8 hours for entire month close process So much better
class PaymentWorker def perform(amount) current_balance = user.balance if current_balance != amount # charge user? throw error? do nothing? else charge_user(amount) end end end
From: [email protected] Subject: Your August 2017 Invoice Hi Anthony, Thanks for being a loyal customer! As of 2017-08-07 19:31:09 PST, your balance is $10.00. Thanks, DigitalOcean
From: [email protected] Subject: Your August 2017 Invoice Hi Anthony, Thanks for being a loyal customer! As of 2017-08-07 19:31:09 PST, your balance is $10.00. As of 2017-08-08 03:31:09 CET, your balance is Ft2565. Thanks, DigitalOcean