Best way to send out batches of emails on the hour according to user prefs

We have an application that sends out a daily email to every user, but we allow the user to specify what hour of the day they want to receive the email.

They can set their timezone and delivery hour in their user preferences.

We set up something rather complicated with sidekiq; a job that runs every 24 hours and queues up all the email sending for the next 24 hours based on user preferences. But if a user changes his preference, the previously queued email will still go out.

But I’d rather use a simple rake task that just runs hourly, checks the user’s email prefs, and sends out his email if he has elected to receive email at that specific hour. If that is a rake task should I still use a background job to send the emails just in case the rake task breaks halfway through? And I’m also not sure how this can be done most simply; what is the best way to have a scheduled task that knows which emails have yet to be sent for that day?

If I’m coming at this in a weird way I’d like to know.

I have a similar setup that is driven by a cron job that checks for preferences saved in a database, queues jobs via ActiveJob / Sidekiq (assuming this is Rails 4+), and sends notifications. It works really well. .perform_later on a ActiveJob object is where the rubber meets the road. I kept referencing this blog post. Good luck!

tl;dr: Yes, use ActiveJob / Sidekiq; see blog post.

One thing you’re going to want to do on that hourly job is make sure that emails for previous hours that day got delivered. If you have a process running slowly or an outage that delays email delivery, your users will probably want the email even if it’s an hour late.

I don’t think Sidekiq is all that complicated to run. It has a nice API (you can use most of its features through Active Job if that’s important to you), has a decent web interface, and behaves in a sane fashion without any custom setup. We run millions of jobs at Cortex and it’s one the most important and least problematic components of our tech stack.