Schedule background jobs in Rails with Integromat
The most common tool for background jobs in Ruby on Rails is Sidekiq. Unfortunately, it's not standalone and it has Redis as a dependency. In this post, I will present an alternative approach for scheduling tasks in Rails.
Oh come on! What's the problem with Sidekiq? It's well tested and widely used in many production apps!
Please remember that I focus on product bootstrapping. Time to market is crucial. I'm also a one-man army and I try to minimize any unneeded maintenance.
To be able to use Sidekiq you need to set up and maintain a new service with Redis. It takes time and effort. I was looking for a solution to quickly implement scheduled jobs without any overhead for my Rails app: Get a Product Job.
Fine, why cannot you just use cron?
I'm using Render and its services don't have cron out of the box.
Solution
I decided to use Integromat. It's a tool for automating processes and it has an attractive free tier (1000 operations/month). Just enough for small side projects.
How to glue it with the Ruby on Rails app?
- Create a new controller with an action containing your task in
app/controllers/background_jobs_controller.rb
:
class BackgroundJobsController < ApplicationController
def cleanup
async_rake "background:cleanup"
# you can also pass environment variables as follows:
# async_rake "background:cleanup", :dry_run => "false"
head :ok
end
end
- Define a method to execute rake tasks asynchronously in
app/controllers/application_controller.rb
.
def async_rake(task, options = {})
options[:rails_env] ||= Rails.env
env_vars = options.map { |key, value| "#{key.to_s.upcase}='#{value.to_s}'" }
env_vars_string = env_vars.join(' ')
log_file = File.join(Rails.root, "log/async_rake.#{Rails.env}.log")
Process.fork {
exec("#{env_vars_string} bin/rake #{task} --trace 2>&1 >> #{log_file}")
}
end
Implementation from https://gist.github.com/tompave/ae53fbab32ebebf1072e
- Create a rake task
lib/tasks/background.rake
to perform any background logic you need:
namespace :background do
task :cleanup => :environment do
puts "👋 from the background task!"
end
end
- Add a new route in config/routes.rb
post '/task/cleanup', to: 'background_jobs#cleanup'
-
Go to Integromat and create a new scenario.
-
Select HTTP and click click Continue.
-
Click on HTTP and select Make a request.
-
Configure Integromat to make a request to
/task/cleanup
endpoint you just set up in the Rails app.
-
After saving a request click on a clock icon to configure when to send a request.
-
Set up when to fire your background task.
-
Save the scenario and that's all! You can run it once to test the whole setup.
Summary
What are the pros and cons of this approach?
✅ Quick implementation.
✅ No new layers to maintain (Redis + Sidekiq).
✅ Money saved on new services (quite important when you're just starting out and validating ideas).
🚨 Not the safest solution. You might consider adding authorization or at least server-side checks to make sure that the task is not run too often.
🚨 For some of you, Integromat free tier might not be enough.
🚨 If not careful, you can easily exceed Integromat's free tier.