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.
- checksums.yaml +4 -4
- data/README.md +284 -25
- data/VERSION +1 -1
- data/lib/rails_pod_kit/config.rb +28 -2
- data/lib/rails_pod_kit/error_reporter.rb +34 -0
- data/lib/rails_pod_kit/exporter.rb +42 -0
- data/lib/rails_pod_kit/global_exporter.rb +27 -9
- data/lib/rails_pod_kit/global_scheduler.rb +156 -0
- data/lib/rails_pod_kit/shutdown.rb +18 -0
- data/lib/rails_pod_kit/sidekiq.rb +5 -12
- data/lib/rails_pod_kit/solid_queue/metrics.rb +186 -0
- data/lib/rails_pod_kit/solid_queue/scheduler_runner.rb +118 -0
- data/lib/rails_pod_kit/solid_queue.rb +108 -0
- data/lib/rails_pod_kit/supervisor.rb +90 -0
- data/lib/rails_pod_kit.rb +8 -5
- metadata +32 -7
|
@@ -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
|
|
10
|
-
# format on an in-process /metrics endpoint (default port
|
|
11
|
-
# no separate collector process. A thin wrapper around the
|
|
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
|
|
26
|
-
# entrypoint
|
|
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
|
|
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
|
|
127
|
-
|
|
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
|
|
171
|
-
and health checks'
|
|
195
|
+
summary: 'Operational endpoints for Rails pods: Prometheus metrics (Puma, Sidekiq,
|
|
196
|
+
SolidQueue) and health checks'
|
|
172
197
|
test_files: []
|