Skip to content
LastPing
GUIDE · SIDEKIQ · FREE

Monitor Sidekiq cron jobs: server middleware ping on success and failure

A Sidekiq server middleware wraps yield in begin/rescue: on success it GETs the ping URL; in rescue it POSTs the exception text to /fail and re-raises. Register it once in Sidekiq.configure_server to cover every worker. Pair with sidekiq-cron for scheduled jobs. Absence detection handles a down Sidekiq process. Free, no monitor cap.

Your assistant can do this for you

Monitor my Sidekiq jobs with LastPing

On this page
  1. The snippets
  2. What this catches
  3. Questions people ask

The snippets

Create a monitor in the console, set the schedule to match your sidekiq-cron expression plus a grace window, and copy the ping URL.

Global server middleware: covers all workers

Store the ping URL as a constant on the worker class so each worker can have its own monitor. The middleware reads it via worker.class::PING if defined, or falls back to a default:

require 'net/http'
require 'uri'

module LastPingMiddleware
  class Server
    def call(worker, _job, _queue)
      ping_url = worker.class.const_defined?(:PING) ?
        worker.class::PING :
        ENV['LASTPING_DEFAULT_URL']
      return yield unless ping_url  # skip unmonitored workers

      begin
        yield  # run the job
        Net::HTTP.get(URI(ping_url))
      rescue => e
        body = "#{e.class}: #{e.message}"[0, 10_000]
        uri  = URI("#{ping_url}/fail")
        req  = Net::HTTP::Post.new(uri)
        req.body = body
        Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
        raise
      end
    end
  end
end

Sidekiq.configure_server do |config|
  config.server_middleware do |chain|
    chain.add LastPingMiddleware::Server
  end
end

Worker with its own PING constant

Each worker declares PING as a constant. The middleware picks it up automatically, so no additional configuration is needed when you add a new monitored worker:

class DailyReportJob
  include Sidekiq::Job

  PING = "https://ping.lastping.dev/<your-monitor-id>"

  def perform
    # your job logic
    generate_report
    upload_to_s3
  end
end

sidekiq-cron schedule

Register the cron schedule in an initializer or a YAML file. The middleware monitors the same job class regardless of whether it was enqueued manually or by the cron scheduler:

# config/initializers/sidekiq_cron.rb
require 'sidekiq-cron'

Sidekiq::Cron::Job.load_from_hash({
  'daily_report' => {
    'cron'  => '0 2 * * *',
    'class' => 'DailyReportJob',
  },
  'weekly_cleanup' => {
    'cron'  => '0 3 * * 1',
    'class' => 'WeeklyCleanupJob',
  },
})

Why re-raise matters here too

Re-raising after the /fail ping keeps Sidekiq's built-in retry semantics intact. The job retries according to its sidekiq_options retry: configuration, and Sidekiq's dead-set captures it if all retries fail. The LastPing ping adds fast alerting on top: it doesn't replace Sidekiq's error handling. See also the Ruby script monitoring guide for the plain-script pattern and the cron guide for OS-level scheduling. AI agents can provision monitors via the LastPing MCP server.

What this catches

The middleware reports what it can; the silence reports the rest.

  • A Ruby exception in the job: middleware rescues, POSTs to /fail, and re-raises so Sidekiq's retry logic still applies.
  • Successful job completion: yield returns without raising; the success ping resets the absence timer.
  • Sidekiq process killed: in-flight jobs are lost; no success ping arrives; the absence opens the incident after the grace window.
  • sidekiq-cron is down: no jobs are enqueued; absence → incident.
  • Recovery: the next successful job run triggers the success ping, closing the incident automatically.

Questions people ask

Front-loaded answers: the most important fact first.

  • How do I monitor a Sidekiq cron job with LastPing?

    Add a Sidekiq server middleware that wraps the yield call in begin/rescue: on success GET the ping URL with Net::HTTP; in rescue POST the exception text to /fail and re-raise. Register it in Sidekiq.configure_server.

  • Does the middleware run for every worker or just specific ones?

    Server middleware runs for every job by default. To scope it to specific workers, store the ping URL in a PING constant on the worker class so each worker can have its own monitor: the constant check gates which workers actually trigger a ping, and workers without the constant are skipped with return yield. You can also check the worker class inside the middleware using worker.class.name.

  • How does sidekiq-cron fit in?

    sidekiq-cron schedules Sidekiq jobs on a cron expression. The jobs themselves run through the normal Sidekiq worker pipeline, so the middleware approach monitors them without any changes to the cron configuration.

  • What if Sidekiq itself is down?

    If Sidekiq is not running, no jobs are processed and no middleware fires. Absence-detection monitoring catches this: the missing ping after the grace window opens an incident, with no running Sidekiq process or worker required on the failure detection side.

  • Can I use Faraday instead of Net::HTTP in the middleware?

    Yes. Any HTTP client works inside the middleware's call method. Faraday, HTTParty, or Net::HTTP from the stdlib are all valid choices. The ping is a plain GET or POST.

  • Is Sidekiq cron monitoring free?

    Yes. LastPing is free for individuals with no monitor cap. See how it compares to Healthchecks.io and Cronitor.

FREE FOR INDIVIDUALS · FULLY HOSTED

Register once, cover every Sidekiq worker you'll ever add.

One middleware class now beats a silent background job later. First alert wired up in about a minute, and LastPing monitors itself the same way.