Rails 7. StartKit +“whenever” gem
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.
I found that it could be really easy to manage cron jobs with a rails gem whenever. That is how it may look
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.
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
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.
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
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!