Rails Cron Jobs - Task Scheduling In Rails

Rails Cron Jobs - Task Scheduling In Rails

Everything you need to know about Cron Jobs in Rails

Have you ever found yourself in a situation where you needed to schedule tasks to run automatically? It could be things like sending daily emails or regularly syncing data with an external API. That's where Cron jobs come in handy. They allow you to automate these tasks effortlessly. In this blog, I'll introduce you to Cron, a fundamental software integrated into Unix/Linux systems for running scheduled tasks. I'll also provide a quick guide on using the Ruby Whenever Gem to easily deploy Cron jobs specifically in Rails applications.

What Are Cron Jobs?

Before we dive into the usage of Cron Jobs in Rails with the Whenever Gem, let me provide you with a simple explanation of what a cron job is. (I'll be writing a detailed article on this topic soon)

In basic terms, Cron is a command line tool that allows you to schedule and run recurring tasks at specific times. These tasks are called cron jobs. Since Cron is built into Linux/Unix systems, you don't need to install any additional dependencies. Typically, cron jobs are written in a file called crontab, which stands for Cron Table. The syntax of a crontab task/cron job consists of five numbers separated by spaces, representing when a task should be executed, followed by the script to run. The syntax should look like this:

# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday;
# │ │ │ │ │ 7 is also Sunday on some systems)
# │ │ │ │ │
# │ │ │ │ │
# * * * * * command to execute

The diagram below illustrates the syntax well:

While it is possible to schedule Rails jobs using the crontab, it can feel outdated and cumbersome. The process involves using the command:

0 * * * * 'cd path/to/project && bundle exec some_task'

Whenever Gem

Now, let me explain a better way to handle cron jobs in Rails. Instead of dealing with the traditional and somewhat messy crontab, there's a Ruby Gem that makes scheduling cron jobs much simpler and more elegant. The go-to gem for this purpose is called Whenever.

Whenever is a gem that streamlines the process of setting up cron jobs. Rather than manually editing the crontab, you can write your cron jobs in Ruby code using Whenever. This gem takes care of updating the crontab for you. We can

Setting Up Whenever Gem

Now let's set up the gem in our application and use it. We will start with the installation of the gem. Just include the gem in your Gemfile, as shown below, and run bundle install.

gem 'whenever', require: false

Now let's initialize the gem by running

bundle exec .wheneverize

When you run the .wheneverize command, it will create a file named schedule.rb in the config directory, specifically config/schedule.rb. This file is responsible for defining the timing for job execution and specifying the Rake task to be executed.

Now once the gem is set up, let's move toward actually scheduling a job. For that, you will start by creating a Rake task.

rails g task batch send_messages

Once the rake task is created, the file for the task can be found in lib/tasks/sample.rb. Now, let's add a functionality to send emails in it.

# lib/tasks/send_messages.rake

namespace :messages do
  desc "Send messages to users"
  task send: :environment do
    User.all.each do |user|
      MessageMailer.send_message(user.email).deliver_now
      puts "Message sent to #{user.email}"
    end
  end
end

Once we have added the logic to our Rake task, we can register it in the schedular.rb file. In our example, let's give it 1 minute.

every 1.minute do
    rake 'messages:send'
end

Then we will update our crontab and will add the job there by running the command

whenever --update-crontab

Your Cron Job has been successfully set up. It has been scheduled to run at a specified time. Additionally, you have the option to clear your crontab using the command whenever --clear-crontab and view the crontab using crontab -l.

Sidekiq-Cron Gem

Sidekiq-cron is an add-on for Sidekiq, a job processing library. Sidekiq-cron allows you to schedule jobs to run at specific times or intervals. It's important to note that Sidekiq-cron is not an official gem provided by Sidekiq.

In Sidekiq, scheduling jobs is typically considered an enterprise-level feature that may require a paid license. However, if you don't want to spend money on the enterprise version, Sidekiq-cron is a suitable alternative for you.

In simpler terms, Sidekiq-cron is a tool that enables you to schedule jobs within Sidekiq without having to pay for the official enterprise version. It provides similar scheduling capabilities, allowing you to specify when and how often your jobs should run.

Setting Up Sidekiq-Cron Gem

Now let's set up the Sidekiq-Cron gem in our application. We will start with the installation of the gem. Just include the gem in your Gemfile, as shown below, and run bundle install.

gem 'sidekiq-cron'

Then create a schedule.yml in the config/ directory, just like it was done in Whenever Gem's case. Although, unlike Whenever, Sidekiq-Cron does not provide a scaffolding mechanism to initialize the file. We will also be creating another file in config/initializers with the name sidekiq.rb with the following content in it

schedule_file = "config/schedule.yml"
if File.exist?(schedule_file) && Sidekiq.server?
   Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file)
end

After this our initial configuration is complete. Now it's time to create the actual job. For that go to the terminal and type

rails generate job send_bulk_emails

And then add some functionality to this code.

NOTE: For a detailed tutorial on how to set up, create and use Rails Background Jobs/Workers please refer to this article.

class SendBulkEmailJob < ApplicationJob
  queue_as :default

def perform(emails)
    begin
      BulkEmailService.send_emails(emails)
    rescue StandardError => e
      Rails.logger.error "Error sending bulk emails: #{e.message}"
      raise e
    end
  end
end

After making the Job, run it by typing sidekiq in the terminal and add the created job to the schedular file like this:

email_job:
   cron: "*/5 * * * *"
   class: "SendBulkEmailJob"

To run the worker, open a new tab in the terminal. It's important to note that the worker should continue running while the app is active. If you need to run other commands like starting the Rails server or any other tasks, make sure to switch to a different tab.

That's all! Congratulations on creating your first sidekiq-cron job. Celebrate your accomplishment!

Conclusion

In summary, Cron jobs are essential for automating recurring tasks in Unix/Linux systems. The Whenever gem simplifies scheduling cron jobs in Rails applications by allowing you to write them in Ruby code and automatically updating the crontab. Sidekiq-Cron is a useful gem for scheduling jobs in Sidekiq. Both gems streamline the process of managing and executing cron jobs, improving automation and efficiency in your application.

In future articles, we'll explore more about how Rails works behind the scenes. So make sure to stay tuned and keep learning!