Module: RailsPodKit::GlobalExporter

Defined in:
lib/rails_pod_kit/global_exporter.rb

Overview

Standalone, always-on exporter for the Sidekiq global (Redis-wide) queue metrics (queue latency, jobs waiting, scheduled/retry/dead counts, …).

Runs as its own 1-replica Deployment so those series come from a single source, fully decoupled from web/worker autoscaling: KEDA can scale the web and worker pods (even to zero) without the queue metrics disappearing or being duplicated per pod. It is NOT a Sidekiq server and serves no web traffic — it just reads the cluster stats from Redis and exposes them on the exporter port.

Deliberately Rails-free. The whole job is reading a handful of counters from Redis, so booting the host app (every gem, every initializer) just to inherit the connection config would cost hundreds of Mi RSS for nothing. Instead the host injects its Redis options into run!, which configures the Sidekiq client itself — the process sits at ~60Mi.

Entry point: a thin, host-owned executable (the gem ships none, so the host keeps full ownership of its connection config), e.g. bin/pod-exporter:

#!/usr/bin/env ruby
require 'bundler/setup'
require 'rails_pod_kit/global_exporter'
RailsPodKit::GlobalExporter.run!(redis: { url: ENV['REDIS_URL'] })

Being an always-on singleton also makes it the natural host for the sidekiq-cron poller (scheduler: true, see GlobalScheduler), which is what lets the workers scale to zero without losing their schedule.

Class Method Summary collapse

Class Method Details

.configure_redis!(redis_options) ⇒ Object

Configure the Sidekiq client's Redis connection so this Rails-free process can read the cluster stats.



88
89
90
91
92
93
# File 'lib/rails_pod_kit/global_exporter.rb', line 88

def configure_redis!(redis_options)
  require 'sidekiq'
  ::Sidekiq.configure_client do |config|
    config.redis = redis_options
  end
end

.install!Object

Force-enable cluster collection so yabeda declares the global gauges when it configures. Force-on regardless of the host's sidekiq_global_metrics policy — collecting them is this process's whole job; the web/worker pods stay :off so they don't duplicate it.



42
43
44
45
46
# File 'lib/rails_pod_kit/global_exporter.rb', line 42

def install!
  require 'rails_pod_kit/sidekiq'
  require 'yabeda/prometheus/mmap'
  RailsPodKit::Sidekiq.enable_global_collection!
end

.run!(redis:, scheduler: false, **scheduler_options) ⇒ Object

Boots the exporter and blocks. Self-sufficient: no Rails environment is required — it wires the Sidekiq client's Redis connection from the host-injected options, declares and configures the gauges, starts the metrics server, then sleeps.

redis: takes the same options hash the host passes to its own Sidekiq.configure_* blocks (url:, ssl_params:, …), so the connection config stays a host decision with a single source of truth.

scheduler: true additionally runs the sidekiq-cron poller here; any extra keywords are GlobalScheduler.start!'s (schedule_file:, poll_interval:, supervision_interval:). The scheduler is not gated on RailsPodKit.enabled? — that switch owns the metrics exporter, and an app may well want the singleton scheduler with metrics turned off.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/rails_pod_kit/global_exporter.rb', line 63

def run!(redis:, scheduler: false, **scheduler_options)
  serve_metrics = RailsPodKit.enabled?
  warn '[rails_pod_kit] disabled — /metrics not served by the global exporter' unless serve_metrics
  return unless serve_metrics || scheduler

  configure_redis!(redis)
  start_metrics! if serve_metrics
  GlobalScheduler.start!(**scheduler_options) if scheduler

  # Both the exporter and the poller serve from background threads; block
  # the main thread so the process stays up until the kubelet sends SIGTERM.
  Shutdown.await
  GlobalScheduler.stop! if scheduler
end

.start_metrics!Object



78
79
80
81
82
83
84
# File 'lib/rails_pod_kit/global_exporter.rb', line 78

def start_metrics!
  install!
  RailsPodKit::Sidekiq.start_metrics_server!

  require 'yabeda'
  Yabeda.configure! unless Yabeda.already_configured?
end