Executing Background Tasks With Scheduler in Rails

Executing Background Tasks with Scheduler in Rails

rufus-scheduler is a handy gem that allows you to perform background jobs. In this article we will show you how to use rufus-scheduler in your Rails applications. Let’s get started:

Setup

In order to use rufus-scheduler, we must first add the rufus-scheduler gem to our Gemfile. To do this, open up your Gemfile and add in the line listed below:

Gemfile
1
gem 'rufus-scheduler'

Run a bundle install to install the gem:

1
bundle install

Great, we need to create an initializer that will contain the jobs we wish to schedule. Create a new initializer called scheduler.rb in the config/initializers directory and add in the code listed below:

config/initializers/scheduler.rb
1
2
3
4
5
require 'rufus-scheduler'

scheduler = Rufus::Scheduler::singleton

# jobs go below here.

Now we are ready to schedule jobs.

Scheduling the Jobs

rufus-scheduler provides a simple syntax for scheduling jobs. You can schedule both one time jobs and recurring jobs. One time jobs can be either scheduled at a specific time, or you can tell rufus to wait a specific amount of time before running the job (a delayed job). For recurring jobs and delayed jobs, you can either use a simple plain English (30m = 30 minutes, etc.) format or you can use the cron format for scheduling jobs. For this article we’ll focus on the English format:

Recurring the Jobs
Scheduling recurring jobs is easy. Simply use the following format in your scheduler.rb file:

config/initializers/scheduler.rb
1
2
3
scheduler.every '5s' do
  # do stuff
end

The code above would perform your background task every 5 seconds. The list below will give you an idea of what time units are supported:

s Example: 5s - seconds, specifies the number of seconds you wish to wait.
m Example: 5m - the number of minutes you wish to wait.
h Example: 5h - the number of hours you wish to wait.
d Example: 5d - the number of days you wish to wait.
w Example: 5w - the number of weeks you wish to wait.
M Example: 5M - the number of months you wish to wait.
y Example: 1y - the number of years you wish to wait.

For example, the following code would tell rufus you wish to schedule a job for every 11 and a half hours:

config/initializers/scheduler.rb
1
2
3
scheduler.every '11h30m' do
  # do stuff
end

Scheduling a delayed job is easy. The syntax is similar to the recurring syntax listed above, but we use the .in method instead of .every. For example, the following code would run a task 4 hours after the server starts:

config/initializers/scheduler.rb
1
2
3
scheduler.in '4h' do
  # do stuff
end

Scheduling the Jobs for Specific Dates/Times
You can also schedule a job for a specific date and time. To do this we use the at method. For example, the following code would run at 12:01am on December 1st, 2017:

config/initializers/scheduler.rb
1
2
3
scheduler.at '2017/12/01 00:01:00' do
  # do stuff
end

Important Caveats

1. Because rufus-scheduler runs in process, the scheduler will reset if your Rails server gets restarted. This means that the timer for your jobs will get reset, so don’t count on any monthly or yearly jobs getting called. If you need to persist jobs across server resets, use a job backend. We will show you how to do this in another article.
2. Rufus does not work with Active Job.
3. Some additional setup is needed for production environments (see below).

Production Setup

Production servers require a bit of additional setup. On most production web servers, idle Ruby processes are killed. In order for rufus to work, you’ll need to stop this from happening. For Passenger/Nginx you can copy the following code below to your nginx.conf config file for your website after the line that says passenger_enabled on;.

nginx.conf
1
2
3
passenger_spawn_method direct;
passenger_min_instances 1;
passenger_pool_idle_time 0;

rufus-scheduler is a simple, easy to use scheduler that provides great functionality. It can be used for stuff like sending emails, cleaning up temp files, and much more.

So far so good, That’s it!!! See ya!!! :)