rails_health_checks 0.6.0 → 0.7.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 +8 -3
- data/app/controllers/rails_health_checks/application_controller.rb +12 -0
- data/config/routes.rb +2 -2
- data/lib/rails_health_checks/check_registry.rb +2 -1
- data/lib/rails_health_checks/checks/http_check.rb +6 -2
- data/lib/rails_health_checks/configuration.rb +22 -2
- data/lib/rails_health_checks/engine.rb +4 -0
- data/lib/rails_health_checks/result_cache.rb +25 -0
- data/lib/rails_health_checks/version.rb +1 -1
- data/lib/rails_health_checks.rb +5 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cf33a3b43064f931e789b7d28fff6145c206229b14da15d4da208717007f2c44
|
|
4
|
+
data.tar.gz: 85c221c95529597327d5a830c9dc6f46da3720133cc19b2366be7af3256f0f57
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5f460a617a378811cceda76d3993f589424af6b8bca336a00f2e887cdcc540f1bf29a6a0f049dd7a1a19c8944efff566f92e567a70380651983ed95e106abaa3
|
|
7
|
+
data.tar.gz: ec5f9be2fc4ad1d84582006455cb742c010232b4e65c0f99f8d4782429d48bda9973e0f6f9e9074bc1d799a03b5e856daf650adc8c0b2dda4637242a7844ede9
|
data/README.md
CHANGED
|
@@ -57,6 +57,8 @@ mount RailsHealthChecks::Engine => "/health"
|
|
|
57
57
|
| `GET /health/live` | Plain text | Load balancer liveness probes |
|
|
58
58
|
| `GET /health/metrics` | Prometheus text | Prometheus / OpenMetrics scraping |
|
|
59
59
|
|
|
60
|
+
`/health` and `/health/live` also respond to `HEAD` requests (useful for lightweight load balancer probes).
|
|
61
|
+
|
|
60
62
|
HTTP status is `200 OK` when all checks pass, `503 Service Unavailable` otherwise (except `/metrics` which always returns `200`).
|
|
61
63
|
|
|
62
64
|
### JSON response shape
|
|
@@ -82,11 +84,14 @@ Status values: `ok` | `degraded` | `critical`. Overall status is `critical` if a
|
|
|
82
84
|
```ruby
|
|
83
85
|
# config/initializers/rails_health_checks.rb
|
|
84
86
|
RailsHealthChecks.configure do |config|
|
|
85
|
-
config.checks
|
|
86
|
-
config.timeout
|
|
87
|
+
config.checks = [:database, :cache] # checks to run (default: [:database])
|
|
88
|
+
config.timeout = 5 # global timeout per check in seconds (default: 5)
|
|
89
|
+
config.cache_duration = 10 # cache results for N seconds (default: nil, disabled)
|
|
87
90
|
end
|
|
88
91
|
```
|
|
89
92
|
|
|
93
|
+
Configuration is validated at boot time. An unknown check name or a missing `http_url` for the `:http` check raises `RailsHealthChecks::ConfigurationError` on startup rather than silently failing on the first request.
|
|
94
|
+
|
|
90
95
|
[↑ Back to top](#table-of-contents)
|
|
91
96
|
|
|
92
97
|
---
|
|
@@ -139,7 +144,7 @@ The block receives the `ActionDispatch::Request` object and must return a truthy
|
|
|
139
144
|
| `:resque` | Resque Redis connectivity; optional `config.resque_queue_size` threshold for total queue depth |
|
|
140
145
|
| `:disk` | Free disk bytes via `df`; optional `config.disk_warn_threshold` / `config.disk_critical_threshold` (bytes) and `config.disk_path` (default: `/`) |
|
|
141
146
|
| `:memory` | Process RSS via `ps`; optional `config.memory_threshold` (bytes) reports `degraded` when exceeded |
|
|
142
|
-
| `:http` | HTTP GET to `config.http_url`; reports `critical` if response code differs from `config.http_expected_status` (default: `200`) or a network error occurs |
|
|
147
|
+
| `:http` | HTTP GET to `config.http_url`; reports `critical` if response code differs from `config.http_expected_status` (default: `200`) or a network error occurs; optional `config.http_headers` hash sends custom request headers (e.g. `{ "Authorization" => "Bearer ..." }`) |
|
|
143
148
|
|
|
144
149
|
[↑ Back to top](#table-of-contents)
|
|
145
150
|
|
|
@@ -9,6 +9,18 @@ module RailsHealthChecks
|
|
|
9
9
|
|
|
10
10
|
def run_checks(check_names)
|
|
11
11
|
config = RailsHealthChecks.configuration
|
|
12
|
+
|
|
13
|
+
if config.cache_duration
|
|
14
|
+
cache_key = check_names.map(&:to_s).sort.join(",")
|
|
15
|
+
RailsHealthChecks.result_cache.fetch(cache_key, ttl: config.cache_duration) do
|
|
16
|
+
build_and_run(check_names, config)
|
|
17
|
+
end
|
|
18
|
+
else
|
|
19
|
+
build_and_run(check_names, config)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def build_and_run(check_names, config)
|
|
12
24
|
checks = CheckRegistry.build(check_names)
|
|
13
25
|
CheckRegistry.run(checks, timeout: config.timeout)
|
|
14
26
|
end
|
data/config/routes.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
RailsHealthChecks::Engine.routes.draw do
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
match "/", to: "health#show", as: :health, via: [:get, :head]
|
|
5
|
+
match "/live", to: "live#show", as: :health_live, via: [:get, :head]
|
|
6
6
|
get "/metrics", to: "metrics#show", as: :health_metrics
|
|
7
7
|
get "/:id", to: "groups#show", as: :health_group
|
|
8
8
|
end
|
|
@@ -15,7 +15,8 @@ module RailsHealthChecks
|
|
|
15
15
|
memory: -> { Checks::MemoryCheck.new(threshold: RailsHealthChecks.configuration.memory_threshold) },
|
|
16
16
|
http: -> { Checks::HttpCheck.new(
|
|
17
17
|
url: RailsHealthChecks.configuration.http_url,
|
|
18
|
-
expected_status: RailsHealthChecks.configuration.http_expected_status
|
|
18
|
+
expected_status: RailsHealthChecks.configuration.http_expected_status,
|
|
19
|
+
headers: RailsHealthChecks.configuration.http_headers
|
|
19
20
|
) },
|
|
20
21
|
disk: -> { Checks::DiskCheck.new(
|
|
21
22
|
warn_threshold: RailsHealthChecks.configuration.disk_warn_threshold,
|
|
@@ -6,14 +6,18 @@ require "uri"
|
|
|
6
6
|
module RailsHealthChecks
|
|
7
7
|
module Checks
|
|
8
8
|
class HttpCheck < Check
|
|
9
|
-
def initialize(url:, expected_status: 200)
|
|
9
|
+
def initialize(url:, expected_status: 200, headers: {})
|
|
10
10
|
@url = url
|
|
11
11
|
@expected_status = expected_status
|
|
12
|
+
@headers = headers
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def call
|
|
15
16
|
measure do
|
|
16
|
-
|
|
17
|
+
uri = URI.parse(@url)
|
|
18
|
+
request = Net::HTTP::Get.new(uri)
|
|
19
|
+
@headers.each { |name, value| request[name] = value }
|
|
20
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(request) }
|
|
17
21
|
code = response.code.to_i
|
|
18
22
|
return fail_with("HTTP GET #{@url} returned #{code}, expected #{@expected_status}") if code != @expected_status
|
|
19
23
|
end
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module RailsHealthChecks
|
|
4
|
+
class ConfigurationError < StandardError; end
|
|
5
|
+
|
|
4
6
|
class Configuration
|
|
7
|
+
BUILT_IN_NAMES = %i[database cache sidekiq solid_queue good_job resque disk memory http].freeze
|
|
8
|
+
|
|
5
9
|
attr_writer :checks
|
|
6
|
-
attr_accessor :timeout, :
|
|
10
|
+
attr_accessor :timeout, :cache_duration, :allowed_ips, :token,
|
|
11
|
+
:sidekiq_queue_size, :solid_queue_job_count, :good_job_latency,
|
|
7
12
|
:resque_queue_size, :disk_warn_threshold, :disk_critical_threshold, :disk_path,
|
|
8
|
-
:memory_threshold, :http_url, :http_expected_status
|
|
13
|
+
:memory_threshold, :http_url, :http_expected_status, :http_headers
|
|
9
14
|
attr_reader :authenticate_block, :custom_checks, :groups
|
|
10
15
|
|
|
11
16
|
def initialize
|
|
12
17
|
@checks = [:database]
|
|
13
18
|
@timeout = 5
|
|
19
|
+
@cache_duration = nil
|
|
14
20
|
@allowed_ips = nil
|
|
15
21
|
@token = nil
|
|
16
22
|
@authenticate_block = nil
|
|
@@ -24,6 +30,7 @@ module RailsHealthChecks
|
|
|
24
30
|
@memory_threshold = nil
|
|
25
31
|
@http_url = nil
|
|
26
32
|
@http_expected_status = 200
|
|
33
|
+
@http_headers = {}
|
|
27
34
|
@custom_checks = {}
|
|
28
35
|
@groups = {}
|
|
29
36
|
@disabled_checks = {}
|
|
@@ -53,5 +60,18 @@ module RailsHealthChecks
|
|
|
53
60
|
@custom_checks[name] = check
|
|
54
61
|
@checks << name unless @checks.include?(name)
|
|
55
62
|
end
|
|
63
|
+
|
|
64
|
+
def validate!
|
|
65
|
+
all_checks = @checks + @groups.values.flatten
|
|
66
|
+
all_checks.uniq.each do |name|
|
|
67
|
+
next if BUILT_IN_NAMES.include?(name) || @custom_checks.key?(name)
|
|
68
|
+
|
|
69
|
+
raise ConfigurationError, "Unknown check :#{name}. Built-ins: #{BUILT_IN_NAMES.join(', ')}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
if @checks.include?(:http) && @http_url.nil?
|
|
73
|
+
raise ConfigurationError, "config.checks includes :http but config.http_url is not set"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
56
76
|
end
|
|
57
77
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsHealthChecks
|
|
4
|
+
class ResultCache
|
|
5
|
+
def initialize
|
|
6
|
+
@store = {}
|
|
7
|
+
@mutex = Mutex.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def fetch(key, ttl:)
|
|
11
|
+
@mutex.synchronize do
|
|
12
|
+
entry = @store[key]
|
|
13
|
+
return entry[:results] if entry && (Process.clock_gettime(Process::CLOCK_MONOTONIC) - entry[:at]) < ttl
|
|
14
|
+
|
|
15
|
+
results = yield
|
|
16
|
+
@store[key] = { results: results, at: Process.clock_gettime(Process::CLOCK_MONOTONIC) }
|
|
17
|
+
results
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def clear
|
|
22
|
+
@mutex.synchronize { @store.clear }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/rails_health_checks.rb
CHANGED
|
@@ -17,6 +17,7 @@ require "rails_health_checks/checks/http_check"
|
|
|
17
17
|
require "rails_health_checks/check_registry"
|
|
18
18
|
require "rails_health_checks/response_builder"
|
|
19
19
|
require "rails_health_checks/prometheus_formatter"
|
|
20
|
+
require "rails_health_checks/result_cache"
|
|
20
21
|
|
|
21
22
|
module RailsHealthChecks
|
|
22
23
|
class << self
|
|
@@ -27,5 +28,9 @@ module RailsHealthChecks
|
|
|
27
28
|
def configuration
|
|
28
29
|
@configuration ||= Configuration.new
|
|
29
30
|
end
|
|
31
|
+
|
|
32
|
+
def result_cache
|
|
33
|
+
@result_cache ||= ResultCache.new
|
|
34
|
+
end
|
|
30
35
|
end
|
|
31
36
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_health_checks
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chuck Smith
|
|
@@ -60,6 +60,7 @@ files:
|
|
|
60
60
|
- lib/rails_health_checks/engine.rb
|
|
61
61
|
- lib/rails_health_checks/prometheus_formatter.rb
|
|
62
62
|
- lib/rails_health_checks/response_builder.rb
|
|
63
|
+
- lib/rails_health_checks/result_cache.rb
|
|
63
64
|
- lib/rails_health_checks/version.rb
|
|
64
65
|
- lib/tasks/rails_health_checks_tasks.rake
|
|
65
66
|
homepage: https://github.com/eclectic-coding/rails_health_checks
|