ruby-on-railsrubyresqueresque-scheduler

Best practice to implement scheduled task execution with Rails?


In my Rails application users can cancel their subscription which should trigger a function that downgrades their account at their current_billing_period_end (this variable is provided by the API of the payment provider). For example a user cancels their subscription on the 12th of April but has a valid subscription until the 1st of March. So the premium entry in the database for this user should be set to false only on the 1st of March.

I have implemented a working solution with Resque and Resque-Scheduler but am now wondering if that might be a bit overkill?

I could instead set a subscription_end_date database entry for the user when the subscription is canceld and set it to current_billing_period_end and then whenever the user authenticates I'd run

if user.premium != false && user.subscription_end_date == Time.now.strftime("%Y-%m-%d")
  user.premium = false
  user.save
end

However, that would mean to run that snippet everytime a user authenticates / the frontend checks whether the user is logged in or not through my API.

My question is: what is the better way to implement that functionality? The Resque solution seems cleaner but I wonder if it's too much / taxing for what I'm trying to achieve here. I have never worked with Resque before and if it's another thing I don't have to maintain in production, I'd be happy.


Solution

  • Don't do that.

    It's a bad design to schedule many jobs for a few days or weeks later, especially when they perform a critical task.

    Why?

    Mainly because the scheduled job's date is not stored in your application database but another one, most of the time in Redis. In the majority of cases, it is not included in the backup. So the day you need to restore a backup, you'll lose all pending scheduled job. All the accounts that were pending for the last subscription period to end may remain open.

    The safest solution is to rely on a database field holding the actual end of the subscription date. Let's name it subscription_ends_on. If your user unsubscribes on April 12th, you set subscription_ends_on with the value "March 1rst".

    Then you create a background job that runs every day at midnight and unsubscribe all accounts where subscription_ends_on is not null and is less than or equal to today.