rails_pod_kit 0.0.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'concurrent'
4
+
5
+ require 'rails_pod_kit/error_reporter'
6
+
7
+ module RailsPodKit
8
+ # Keeps a background worker alive on a process that must not lose it.
9
+ #
10
+ # Both schedulers the gem hosts (SolidQueue's, and sidekiq-cron's) run on
11
+ # their own thread inside an always-on process, and both share the same
12
+ # failure mode: the thread dies, the host process notices nothing, and the
13
+ # schedule stops silently. This is that supervision, once — a timer that
14
+ # rebuilds the worker as soon as it stops being alive.
15
+ #
16
+ # The three things that genuinely differ between workers are injected: how to
17
+ # build and start one, how to ask whether it is still alive, and how to wind
18
+ # it down. Everything else — the immediate first tick, the stop latch that
19
+ # keeps a shutdown from being undone by a tick already in flight, reporting
20
+ # instead of dying — is identical and lives here.
21
+ #
22
+ # Deliberately free of Rails: the sidekiq-cron scheduler runs in a Rails-free
23
+ # process, and ErrorReporter degrades to a warning where there is no Rails
24
+ # error reporter to hand the failure to.
25
+ class Supervisor
26
+ DEFAULT_INTERVAL = 30
27
+
28
+ attr_reader :subject
29
+
30
+ # `start:` is a callable returning the started worker. `alive:` and `stop:`
31
+ # take either a method name to send to that worker or a callable receiving
32
+ # it, so the common case stays declarative and a liveness check the worker
33
+ # does not expose itself is still expressible. `stop:` is optional — a
34
+ # worker with no teardown is simply dropped.
35
+ def initialize(source:, start:, alive:, stop: nil, interval: DEFAULT_INTERVAL)
36
+ @source = source
37
+ @start = start
38
+ @alive = alive
39
+ @stop = stop
40
+ @interval = interval
41
+ @stopping = false
42
+ end
43
+
44
+ # Starts the timer, which starts the worker on its first (immediate) tick,
45
+ # and returns without blocking.
46
+ def start
47
+ @stopping = false
48
+ @timer = ::Concurrent::TimerTask.new(execution_interval: @interval, run_now: true) { supervise }
49
+ @timer.execute
50
+ self
51
+ end
52
+
53
+ # Graceful stop: drop the timer first so it cannot resurrect the worker,
54
+ # then wind the worker down rather than leaving it to be cut off.
55
+ def stop
56
+ @stopping = true
57
+ @timer&.shutdown
58
+ @timer = nil
59
+ invoke(@stop, @subject) if @subject && @stop
60
+ @subject = nil
61
+ end
62
+
63
+ def running?
64
+ !!@subject && invoke(@alive, @subject)
65
+ end
66
+
67
+ private
68
+
69
+ def invoke(hook, worker)
70
+ hook.is_a?(::Symbol) ? worker.public_send(hook) : hook.call(worker)
71
+ end
72
+
73
+ # Concurrent::TimerTask silently drops a raising block, so report here and
74
+ # let the next tick retry — a worker that cannot start because its backing
75
+ # store is down must keep trying.
76
+ def supervise
77
+ ensure_running
78
+ rescue StandardError => e
79
+ ErrorReporter.report(e, source: @source)
80
+ end
81
+
82
+ # Idempotent: starts the worker on the first tick, and replaces it only once
83
+ # it has actually stopped being alive.
84
+ def ensure_running
85
+ return if @stopping || running?
86
+
87
+ @subject = @start.call
88
+ end
89
+ end
90
+ end
data/lib/rails_pod_kit.rb CHANGED
@@ -6,9 +6,10 @@ require 'rails_pod_kit/config'
6
6
  # RailsPodKit packages the operational endpoints a Rails pod needs to be a good
7
7
  # Kubernetes citizen behind a single, opinionated entry point:
8
8
  #
9
- # - Prometheus metrics: Puma and Sidekiq runtime metrics in Prometheus text
10
- # format on an in-process /metrics endpoint (default port 9394) — no sidecar,
11
- # no separate collector process. A thin wrapper around the yabeda ecosystem.
9
+ # - Prometheus metrics: Puma, Sidekiq and SolidQueue runtime metrics in
10
+ # Prometheus text format on an in-process /metrics endpoint (default port
11
+ # 9394) — no sidecar, no separate collector process. A thin wrapper around the
12
+ # yabeda ecosystem, plus the SolidQueue queue gauges yabeda has no plugin for.
12
13
  # - Health checks: an opinionated health-monitor-rails configuration serving
13
14
  # liveness/readiness/startup probes on /healthz (see RailsPodKit::Health),
14
15
  # auto-mounted by the gem's Railtie.
@@ -22,8 +23,9 @@ require 'rails_pod_kit/config'
22
23
  # - config/initializers/sidekiq.rb -> RailsPodKit::Sidekiq.install!(config)
23
24
  # - config/initializers/rails_pod_kit.rb -> RailsPodKit.configure { ... }
24
25
  # RailsPodKit::Health.install!(redis: ...)
25
- # plus, only when running the dedicated global exporter, a host-owned
26
- # entrypoint (e.g. bin/pod-exporter) calling GlobalExporter.run!(redis: ...).
26
+ # plus, only when running a dedicated always-on exporter, a host-owned
27
+ # entrypoint calling GlobalExporter.run!(redis: ...) (Sidekiq, Rails-free) or
28
+ # SolidQueue.run_exporter! (SolidQueue, needs the app's ActiveRecord models).
27
29
  #
28
30
  # The gem is deliberately connection-agnostic: it never reads REDIS_URL or
29
31
  # makes TLS decisions. The host injects its Redis options where needed
@@ -57,5 +59,6 @@ require 'rails_pod_kit/config'
57
59
  require 'yabeda/prometheus/mmap'
58
60
 
59
61
  require 'rails_pod_kit/sidekiq'
62
+ require 'rails_pod_kit/solid_queue'
60
63
  require 'rails_pod_kit/health'
61
64
  require 'rails_pod_kit/railtie'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_pod_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fabio Napoleoni
@@ -93,6 +93,20 @@ dependencies:
93
93
  - - "~>"
94
94
  - !ruby/object:Gem::Version
95
95
  version: '2.0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: concurrent-ruby
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '1.2'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.2'
96
110
  - !ruby/object:Gem::Dependency
97
111
  name: health-monitor-rails
98
112
  requirement: !ruby/object:Gem::Requirement
@@ -123,10 +137,13 @@ dependencies:
123
137
  version: '5.0'
124
138
  description: |
125
139
  Packages the yabeda ecosystem and health-monitor-rails into a single,
126
- opinionated kit for running Rails applications on Kubernetes: Puma and
127
- Sidekiq runtime metrics in Prometheus text format on an in-process /metrics
128
- endpoint (default port 9394), plus a /healthz endpoint wired for
129
- liveness/readiness/startup probes. No sidecar, no separate collector.
140
+ opinionated kit for running Rails applications on Kubernetes: Puma, Sidekiq
141
+ and SolidQueue runtime metrics in Prometheus text format on an in-process
142
+ /metrics endpoint (default port 9394), plus a /healthz endpoint wired for
143
+ liveness/readiness/startup probes. No sidecar, no separate collector. It
144
+ also hosts the schedulers that let a job executor scale to zero without
145
+ stranding its recurring jobs: a supervised SolidQueue scheduler thread, and
146
+ a supervised sidekiq-cron poller for Sidekiq.
130
147
  email:
131
148
  - f.napoleoni@gmail.com
132
149
  executables: []
@@ -138,11 +155,19 @@ files:
138
155
  - VERSION
139
156
  - lib/rails_pod_kit.rb
140
157
  - lib/rails_pod_kit/config.rb
158
+ - lib/rails_pod_kit/error_reporter.rb
159
+ - lib/rails_pod_kit/exporter.rb
141
160
  - lib/rails_pod_kit/global_exporter.rb
161
+ - lib/rails_pod_kit/global_scheduler.rb
142
162
  - lib/rails_pod_kit/health.rb
143
163
  - lib/rails_pod_kit/puma.rb
144
164
  - lib/rails_pod_kit/railtie.rb
165
+ - lib/rails_pod_kit/shutdown.rb
145
166
  - lib/rails_pod_kit/sidekiq.rb
167
+ - lib/rails_pod_kit/solid_queue.rb
168
+ - lib/rails_pod_kit/solid_queue/metrics.rb
169
+ - lib/rails_pod_kit/solid_queue/scheduler_runner.rb
170
+ - lib/rails_pod_kit/supervisor.rb
146
171
  - lib/rails_pod_kit/version.rb
147
172
  homepage: https://github.com/fabn/rails_pod_kit
148
173
  licenses:
@@ -167,6 +192,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
192
  requirements: []
168
193
  rubygems_version: 3.6.9
169
194
  specification_version: 4
170
- summary: 'Operational endpoints for Rails pods: Prometheus metrics (Puma + Sidekiq)
171
- and health checks'
195
+ summary: 'Operational endpoints for Rails pods: Prometheus metrics (Puma, Sidekiq,
196
+ SolidQueue) and health checks'
172
197
  test_files: []