Rails 7. StartKit +“whenever” gem

Ilya Zykin
5 min readJan 21, 2023

--

Image by DALL·E

This article tells about Rails 7 and how to install gem whenever to set up periodically executed tasks in a rails application.

Intro

Some weeks ago I’ve started a small Rails 7 dockerized project.
If you a rails developer maybe you already know about Rails 7. StartKit.
Code for this article is places in this PULL REQUEST for Rails 7. StartKit

Old but Gold

Usually Linux servers have very well known service cron preinstalled.

Cron helps to run jobs following a schedule. I never liked a syntax of cron jobs. You need to have some experience to work comfortable with it.

CRON config example from wikipedia

I found that it could be really easy to manage cron jobs with a rails gem whenever. That is how it may look

Example of a whenever config

What is wrong with gem whenever?

Last time this gem was released about 3 years ago. You could say — better do not use it and I can agree.

At the same time it is a helper gem which does very simple thing — generates cron config. I think that probably authors decided that main functionality is done and no need to polish this gem anymore.

Still good enough

Rails 7. StartKit and gem Whenever

As you probably already know I started Rails 7. StartKit to have a playground to learn modern Rails features, because I didn’t touch Rails for last 4 or 5 years. Now it is great to have Rails 7. StartKit to play with whenever. Let’s check if this good solution still work for modern Rails applications.

Typical Periodic task

A most typical periodic task which I would like to run is getting a currency Rate.

Usually in an online store it happens once per a day. In my case I’m going to run the task every minute. It will help me to see how it works without having long delays.

Let’s create a Rails model.

With using Rails 7. StartKit project start the project

bin/start_all
bin/start_all

Go the the Rails container

bin/open rails

Create a model CurrencyRate

rails g model currency_rate from:string to:string rate:float

Rails will create file app/models/currency_rate.rb. Modify it like that

class CurrencyRate < ApplicationRecord
API = "https://api.exchangerate.host/latest"

def self.get(from = "USD", to = "EUR")
uri = URI(CurrencyRate::API + "?base=#{from}&symbols=#{to}")

response = Net::HTTP.get(uri)
response_obj = JSON.parse(response)

create!(
from: from, to: to,
rate: response_obj['rates'][to]
)

puts "[#{DateTime.now.strftime('%d.%m.%Y %H.%M.%S')}]: " + \
"#{from}:#{to} currency rate: " + response_obj['rates'][to].to_s
end
end

Now from the terminal you can run rails runner to execute the code and check if it works correctly

rails runner CurrencyRate.get

USD:EUR currency rate: 0.919716

This result was saved in the database. Let’s open rails development console and check

$ rails c
CurrencyRate.last

Installing Cron

Usually a Linux hosting already have cron service preinstalled and run. For my project I use ruby 3.2 docker image and it does not have it by default.

First I have to install it. That is why I change Dockerfile for my dockerized Rails application. Line 25.

Next I need to run cron when Rails container is started. I do it simply with using some helpers in my bin/ folder helpers.

Cron service has to by started with using root account

These helpers will work when I start/stop my appliaction with using bin/start and bin/stop commands from the folder of my rails application.

Installing whenever

Let’s install a most recent version of whenever. And it is should not be loaded with the rails app.

and as usual install the gem

bundle install

Whenever config file

a typical place of whenever config is config/schedule.rb but I’m going to change this default approach.

For demonstrative purposes I name all config files with CAPITAL letters and make them _UNDERSCORED. So you can find and learn files easier.

Let’s put some code in the whenever config.

# so when CRON is running a task it knows where is your rails exec file
env :GEM_HOME, ENV['GEM_HOME']

# Default environment
set :environment, ENV.fetch("RAILS_ENV") { 'development' }

# Define log files to see what happens with CRON tasks
# I collect all log files in the RAILS_APP_ROOT/log
set :output, {
standard: '/home/lucky/app/log/cron.log',
error: '/home/lucky/app/log/cron.error.log'
}

# My cusotom job runner
job_type :rails, "cd :path && :environment_variable=:environment
bundle exec rails :task :output"

# Run it every minute
every 1.minute do
rails "runner \"CurrencyRate.get('USD', 'EUR')\""
end

Updating CRON schedule

Whenever is installed and config file done, we can see an effect.

First. We should be sure that our environment is restarted and cron service is working.

bin/stop_all
bin/start_all

It should correctly stop rails app, restart everything and cron has to be working.

You do not need it, if you just start Rails 7. StartKit from scratch. Everything must be already preinstalled for you.

Now I’m updating the cron config.

From the Rails application container

 whenever --update-crontab --load-file config/_SCHEDULE.rb -i lucky
From the Rails application container

Or from host machine

bin/exec whenever_start

The result

Result you can see in some minutes in your rails console or in cron logs

Conclusion

Today with using Rails 7. StartKit we have learned how gem whenever can be used to setup periodical jobs in a Rails app.

I hope my open source project Rails 7. StartKit will help you to meet and learn many tools that you can use for Rails development process.

Keep the project on your radar to have more news and learn more about rails development.

Good luck with coding!

--

--

Ilya Zykin
Ilya Zykin

Written by Ilya Zykin

IT coach. React and Rails enthusiast. Passionate programmer, caring husband and pancake baker on Sundays. School teacher of computer studies in the past.

No responses yet