I have been working with a cron-like task scheduler in the past and among the very few options, we choose crono. It works because it allows us to run tasks at 10-second interval and as well as the regular daily/hourly/weekly schedules and most importantly, it runs as a separate process which is good for our Dockerized setup.
Buggy crono
I’m aware of an outstanding bug of crono where it consumes a lot of memory over time. I tried to ignore it but as I have tested it on production overnight, I have no space left for my 40GB disk in my server by the morning. Upon inspecting, it is the crono (via docker ps -s
) that eats up all the disk space with gigabytes of space used by the container over time. Therefore, it is not just that the gem is having memory leak, it has issues with disk space as well. I immediately stopped the container while looking for an alternative.
Rufus Scheduler
Rufus Scheduler seems to be a decent alternative. It runs as a separate process, has rails support and supports schedules at seconds level. One problem that I have is that the rails integration instruction seems awkward as it seems to be running along with the web server process. We always wanted an independent process as we use Docker containers.
Rufus Scheduler, in its simplest form, can be run as a separate process, even without rails. I was wondering if I can load my rails environment while running it as an independent process.
# quickstart.rb require 'rufus-scheduler' scheduler = Rufus::Scheduler.new scheduler.in '10s' do puts 'Runs the task here...' end scheduler.join
Rails runner
Luckily, rails has a command line runner. I just have to combine the rails runner
command and my rufush-scheduler
tasks and I’ll get exactly what I need.
My lib/scheduler.rb
# Don't even have to require anything as the whole rails environment is loaded already scheduler = Rufus::Scheduler.new scheduler.in '10s' do UpdatePricesJob.perform_later if ConfigService.market_open? end scheduler.join
Then run it in the command line like this:
rails runner lib/scheduler.rb
And because it runs in the foreground, it can be wrapped easily into a Docker container.
Easy! Note that I don’t run the task within my task scheduler as I have a worker process powered by shoryuken – a AWS SQS based task processor that I’ve been using since I started coding in Ruby.
Here is my stack for this app:
- Rails web (API)
- Shoryuken for background workers
- Rufus Scheduler for scheduled tasks but are passed to Shoryuken imemdiately
- AWS Lambda + API Gateway for my secret price data source pulling
- Angular for the frontend
That’s it!