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.

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

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

    The middleware runs for every job by default. The PING constant check gates which workers actually trigger a ping — workers without the constant are skipped with return yield.

  • What if Sidekiq itself is down?

    No jobs are processed and no middleware fires. Absence-detection monitoring catches this: the missing ping after the grace window opens an incident — no running Sidekiq process 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 this free?

    Yes. LastPing is free and fully hosted with no monitor cap and no paid tier. See how it compares to Healthchecks.io and Cronitor.

FREE · FULLY HOSTED · NO PAID TIER

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.