3 min read

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?

  1. 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
  1. 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

  1. 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
  1. Add a new route in config/routes.rb
post '/task/cleanup', to: 'background_jobs#cleanup'
  1. Go to Integromat and create a new scenario.
    Screenshot-2021-02-13-at-19.34.08-1

  2. Select HTTP and click click Continue.
    Screenshot-2021-02-13-at-19.34.31-1

  3. Click on HTTP and select Make a request.
    Screenshot-2021-02-13-at-19.39.33-1
    Screenshot-2021-02-13-at-19.39.44-2

  4. Configure Integromat to make a request to /task/cleanup endpoint you just set up in the Rails app.
    Screenshot-2021-02-13-at-19.45.56-1

  5. After saving a request click on a clock icon to configure when to send a request.
    Screenshot-2021-02-13-at-19.44.11-1

  6. Set up when to fire your background task.
    Screenshot-2021-02-13-at-19.44.17-1

  7. 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.


Follow my journey trying to bootstrap a side business.

Powered by EmailOctopus