Scheduling jobs using cron in Rails 4

After deploying an Application, I have to at times do repetitive things like running a rake job, mailing me the log file, clearing the logs, sending newsletter every friday, etc. These are basically some commands I have to run on a regular basis. Running them manually for sometime is great as it allows us to iron out all the errors, but after it stabilizes, there is no reason for us to be doing it manually again and again.

What we need is a way to automate these tasks, which needs to be triggered at specific amounts of time. The most common way of doing this is to use cron, which is available on most UNIX-based (Linux, Mac for example) systems.

If you are a Unix expert, you might have used cron by editing cron files. To edit them, we simply run the command

$ crontab -e

and write the commands in the file that opens. Syntax is a bit tricky but main problem occurs when you start deploying to multiple servers. You would need to write cron file on every server again and update everywhere when necessary.

Enter, whenever ruby gem! It’s the perfect solution for Rails based applications where you need to use cron.

For example, if I want to run a rake task which sends mail every monday at 7:30 AM, I’ll need to write

every :monday, :at => "7:30 am" do
  rake "send_mail:newsletter"

This looks so much better than the cron commands, it scores high on readability points and is easier to remember and change.

For instructions on installation and general usage, you won’t find any better resource than project’s github homepage or the brilliant railscast.

The thing I want to discuss are the issues I faced when my development environment was windows and deployment, Ubuntu!

The very first thing you need to do is set your output to a log file. I had put my output in log/cron.log under my Rails directory.

To do this, write

set :output, 'log/cron.log'

in config/schedule.rb file. This way, all the output from Cron tasks will be shown in log/cron.log file.

Now, the very first problem I faced was it couldn’t find rails.exe in bin/bash. I tried searching on the internet but couldn’t find it. Later, I realized that .exe extension works in windows and not in Ubuntu.

To solve this problem, I opened the file bin/rails and saw

#!/usr/bin/env ruby.exe

written on the very first line there. I immediately removed the .exe extension, commited the repo there and the problem was solved.

By the way, to run open rails console in some other environment, like production, you’d need to write RAILS_ENV=production rails c to make it work. Somehow, rails c RAILS_ENV=production doesn’t work.

At this point, everything was working properly until I deployed my application again. This time, the cron output gave errors about how the rails file was not executable. I later realized that this may be because when I do a git pull, the files in bin folder become read-write and not executable.

This is easy! We just need to do chmod +x bin/rails to make it work. Unfortunately, this wasn’t enough as I forgot to do this every time I pulled from my repo onto the server.

Thus, I added a command type cron job. I wrote in my config/schedule.rb file

command "chmod +x path/to/app/root/bin/rails"

And had it run at 6 in the morning so my jobs, scheduled for 8 AM, 10 AM and 12 AM work without a glitch!

Yup, scheduling jobs is that easy.

Don’t forget to write whenever --update-crontab aap-name to write to cron file. Add it to your capistrano‘s after deploy. You can also add chmod +x execution to capistrano‘s after deploy. Comment out how you used it.

Also, do let me know if you’ve been able to deploy to your VPS while developing on Windows and using capistrano to deploy.


Tags: , , ,