How to Monitor Cron Jobs in Rails
Rails gives you four ways to schedule work. Solid Queue, Sidekiq-cron, whenever and rails runner each need different monitoring.
Rails applications usually schedule work in more than one way, and each mechanism fails differently. Before adding monitoring, find out which ones your application is actually using.
The four you will find are system cron calling rails runner, the whenever gem, a Sidekiq scheduling extension, and, since Rails 8, Solid Queue recurring tasks.
rails runner, and why it is slower than you think
rails runner boots the entire application to execute one line. On a large application that is several seconds of startup before any work begins, every single run.
For a job running every minute, that boot cost is most of your CPU time. That is the argument for moving frequent jobs into a long-running worker process, where the application is already loaded.
Put the monitoring inside the class rather than in the crontab line, so it works identically however the class is invoked.
Sidekiq-cron: two processes, two failure modes
Sidekiq scheduling extensions enqueue jobs on a schedule for Sidekiq workers to execute. The scheduler and the workers can fail independently.
If the scheduler is down, nothing is enqueued and the workers sit idle looking perfectly healthy. If the workers are down, jobs enqueue and accumulate in Redis, and the queue grows while the scheduler reports success at scheduling.
This one job proves both halves at once: the scheduler enqueued it and a worker ran it. It is worth more than monitoring any individual business job, because every business job depends on that pair working.
Also watch queue latency rather than only queue depth. A queue with ten jobs where the oldest is four hours old is a worse signal than a queue with four hundred jobs enqueued in the last minute.
Solid Queue recurring tasks
Rails 8 ships Solid Queue with recurring task support configured in config/recurring.yml, backed by your database rather than Redis.
The dispatcher process is what turns recurring entries into jobs. If your Procfile or systemd unit runs only the worker and not the dispatcher, recurring tasks never fire and the workers process the rest of the queue normally. Nothing looks wrong.
Which mechanism fails how
| Mechanism | Silent failure mode | What catches it |
|---|---|---|
| rails runner via cron | Crontab entry lost on rebuild | Heartbeat interval |
| whenever gem | --update-crontab not run on deploy | Diff crontab -l against whenever output |
| Sidekiq-cron | Scheduler process down | Heartbeat job through the full path |
| Sidekiq workers | Workers down, queue growing | Queue latency alarm plus heartbeat |
| Solid Queue | Dispatcher not running | Heartbeat job |
Do not ping from an initializer
It is tempting to put a startup ping in config/initializers. Resist it. Initializers run during asset precompilation, during rails console, during db:migrate and in every CI job, and each of those produces a ping that says a job succeeded when no job ran.
Keep monitoring calls inside the job or service object, where the thing being monitored actually happens.
Related guides
Plain Ruby scripts are covered in monitoring cron jobs in Ruby, and the Laravel equivalent in monitoring cron jobs in Laravel.