Class: Pinglish
- Inherits:
-
Object
- Object
- Pinglish
- Defined in:
- lib/pinglish.rb,
lib/pinglish/check.rb
Overview
This Rack middleware provides a “/_ping” endpoint for configurable system health checks. It’s intended to be consumed by machines.
Defined Under Namespace
Constant Summary collapse
- HEADERS =
The HTTP headers sent for every response.
{ "Content-Type" => "application/json; charset=UTF-8" }
Instance Method Summary collapse
-
#call(env) ⇒ Object
Exercise the middleware, immediately delegating to the wrapped app unless the request path matches ‘path`.
-
#check(name = nil, options = nil, &block) ⇒ Object
Add a new check with optional ‘name`.
-
#failure?(value) ⇒ Boolean
Does ‘value` represent a check failure? This default implementation returns `true` for any value that is an Exception or false.
-
#initialize(app, options = nil) {|_self| ... } ⇒ Pinglish
constructor
Create a new instance of the middleware wrapping ‘app`, with an optional `:path` (default: `“/_ping”`), `:max` timeout in seconds (default: `29`), and behavior `block`.
-
#timeout(seconds, &block) ⇒ Object
Raise Pinglish::TooLong after ‘seconds` has elapsed.
-
#timeout?(value) ⇒ Boolean
Does ‘value` represent a check timeout? Returns `true` for any value that is an instance of Pinglish::TooLong.
Constructor Details
#initialize(app, options = nil) {|_self| ... } ⇒ Pinglish
Create a new instance of the middleware wrapping ‘app`, with an optional `:path` (default: `“/_ping”`), `:max` timeout in seconds (default: `29`), and behavior `block`.
25 26 27 28 29 30 31 32 33 34 |
# File 'lib/pinglish.rb', line 25 def initialize(app, = nil, &block) ||= {} @app = app @checks = {} @max = [:max] || 29 # seconds @path = [:path] || "/_ping" yield self if block_given? end |
Instance Method Details
#call(env) ⇒ Object
Exercise the middleware, immediately delegating to the wrapped app unless the request path matches ‘path`.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/pinglish.rb', line 39 def call(env) request = Rack::Request.new env return @app.call env unless request.path_info == @path begin timeout @max do results = {} @checks.values.each do |check| begin timeout check.timeout do results[check.name] = check.call end rescue StandardError => e results[check.name] = e end end failed = results.values.any? { |v| failure? v } http_status = failed ? 503 : 200 text_status = failed ? "failures" : "ok" data = { :now => Time.now.to_i.to_s, :status => text_status } results.each do |name, value| # The unnnamed/default check doesn't contribute data. next if name.nil? if failure? value # If a check fails its name is added to a `failures` array. # If the check failed because it timed out, its name is # added to a `timeouts` array instead. key = timeout?(value) ? :timeouts : :failures (data[key] ||= []) << name elsif value # If the check passed and returned a value, the stringified # version of the value is returned under the `name` key. data[name] = value.to_s end end [http_status, HEADERS, [JSON.generate(data)]] end rescue Exception => ex # Something catastrophic happened. We can't even run the checks # and render a JSON response. Fall back on a pre-rendered string # and interpolate the current epoch time. now = Time.now.to_i.to_s [500, HEADERS, ['{"status":"failures","now":"' + now + '"}']] end end |
#check(name = nil, options = nil, &block) ⇒ Object
Add a new check with optional ‘name`. A `:timeout` option can be specified in seconds for checks that might take longer than the one second default. A previously added check with the same name will be replaced.
109 110 111 |
# File 'lib/pinglish.rb', line 109 def check(name = nil, = nil, &block) @checks[name] = Check.new(name, , &block) end |
#failure?(value) ⇒ Boolean
Does ‘value` represent a check failure? This default implementation returns `true` for any value that is an Exception or false. Subclasses can override this method for different behavior.
117 118 119 |
# File 'lib/pinglish.rb', line 117 def failure?(value) value.is_a?(Exception) || value == false end |
#timeout(seconds, &block) ⇒ Object
Raise Pinglish::TooLong after ‘seconds` has elapsed. This default implementation uses Ruby’s built-in Timeout class. Subclasses can override this method for different behavior, but any new implementation must raise Pinglish::TooLong when the timeout is exceeded or override ‘timeout?` appropriately.
127 128 129 |
# File 'lib/pinglish.rb', line 127 def timeout(seconds, &block) Timeout.timeout seconds, Pinglish::TooLong, &block end |