pinglish 0.0.1 → 0.1.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.
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  /*.gem
2
2
  /.bundle
3
+ /Gemfile.lock
data/README.md CHANGED
@@ -29,16 +29,16 @@ conforms to the spec below.
29
29
  serialization or other fundamental code fails.
30
30
 
31
31
  0. The response __must__ contain a `"status"` key set either to `"ok"`
32
- or `"fail"`.
32
+ or `"failures"`.
33
33
 
34
34
  0. The response __must__ contain a `"now"` key set to the current
35
35
  server's time in seconds since epoch as a string.
36
36
 
37
- 0. If the `"status"` key is set to `"fail"`, the response __may__
37
+ 0. If the `"status"` key is set to `"failures"`, the response __may__
38
38
  contain a `"failures"` key set to an Array of string names
39
39
  representing failed checks.
40
40
 
41
- 0. If the `"status"` key is set to `"fail"`, the response __may__
41
+ 0. If the `"status"` key is set to `"failures"`, the response __may__
42
42
  contain a `"timeouts"` key set to an Array of string names
43
43
  representing checks that exceeded an implementation-specific
44
44
  individual timeout.
@@ -56,7 +56,7 @@ conforms to the spec below.
56
56
  // These two keys will always exist.
57
57
 
58
58
  "now": "1359055102",
59
- "status": "fail",
59
+ "status": "failures",
60
60
 
61
61
  // This key may only exist when a named check has failed.
62
62
 
@@ -75,8 +75,6 @@ conforms to the spec below.
75
75
 
76
76
  ## The Middleware
77
77
 
78
- FIX: exegesis
79
-
80
78
  ```ruby
81
79
  require "pinglish"
82
80
 
@@ -108,14 +106,10 @@ use Pinglish do |ping|
108
106
  App.dawdle
109
107
  end
110
108
 
111
- # Signal check failure by raising an exception.
109
+ # Signal check failure by raising an exception. Any exception will do.
112
110
 
113
111
  ping.check :fails do
114
- false or raise "Everything's ruined."
112
+ raise "Everything's ruined."
115
113
  end
116
114
  end
117
115
  ```
118
-
119
- ## Contributing
120
-
121
- FIX
data/lib/pinglish.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "json"
2
- require "timeout"
2
+ require "pinglish/check"
3
3
  require "rack/request"
4
+ require "timeout"
4
5
 
5
6
  # This Rack middleware provides a "/_ping" endpoint for configurable
6
7
  # system health checks. It's intended to be consumed by machines.
@@ -13,42 +14,21 @@ class Pinglish
13
14
  "Content-Type" => "application/json; charset=UTF-8"
14
15
  }
15
16
 
16
- # The maximum amount of time for all checks. 29 seconds, to come in
17
- # just under the 30 second limit of many monitoring services.
18
-
19
- MAX_TOTAL_TIME = 29
20
-
21
- # Represents a check, which is a behavior block with a name and
22
- # timeout in seconds.
23
-
24
- class Check
25
- attr_reader :name
26
- attr_reader :timeout
27
-
28
- def initialize(name, options = nil, &block)
29
- @name = name
30
- @timeout = options && options[:timeout] || 1
31
- @block = block
32
- end
33
-
34
- # Call this check's behavior, returning the result of the block.
35
-
36
- def call(*args, &block)
37
- @block.call *args, &block
38
- end
39
- end
40
-
41
17
  # Raised when a check exceeds its timeout.
42
18
 
43
19
  class TooLong < RuntimeError; end
44
20
 
45
21
  # Create a new instance of the middleware wrapping `app`, with an
46
- # optional `path` (the default is `"/_ping"`) and behavior `block`.
22
+ # optional `:path` (default: `"/_ping"`), `:max` timeout in seconds
23
+ # (default: `29`), and behavior `block`.
24
+
25
+ def initialize(app, options = nil, &block)
26
+ options ||= {}
47
27
 
48
- def initialize(app, path = nil, &block)
49
28
  @app = app
50
29
  @checks = {}
51
- @path = path || "/_ping"
30
+ @max = options[:max] || 29 # seconds
31
+ @path = options[:path] || "/_ping"
52
32
 
53
33
  yield self if block_given?
54
34
  end
@@ -61,63 +41,71 @@ class Pinglish
61
41
 
62
42
  return @app.call env unless request.path == @path
63
43
 
64
- timeout MAX_TOTAL_TIME do
65
- results = {}
44
+ groups = [].map(&:to_s) # FIX
45
+
46
+ begin
47
+ timeout @timeout do
48
+ results = {}
49
+ filtered = @checks.values
66
50
 
67
- @checks.values.each do |check|
68
- begin
69
- timeout check.timeout do
70
- results[check.name] = check.call
51
+ unless groups.empty?
52
+ filtered = filtered.select { |c| groups.include? c.group.to_s }
53
+ end
54
+
55
+ filtered.each do |check|
56
+ begin
57
+ timeout check.timeout do
58
+ results[check.name] = check.call
59
+ end
60
+ rescue StandardError => e
61
+ results[check.name] = e
71
62
  end
72
- rescue StandardError => e
73
- results[check.name] = e
74
63
  end
75
- end
76
64
 
77
- failed = results.values.any? { |v| failure? v }
78
- http_status = failed ? 503 : 200
79
- text_status = failed ? "fail" : "ok"
65
+ failed = results.values.any? { |v| failure? v }
66
+ http_status = failed ? 503 : 200
67
+ text_status = failed ? "failures" : "ok"
80
68
 
81
- data = {
82
- :now => Time.now.to_i.to_s,
83
- :status => text_status
84
- }
69
+ data = {
70
+ :now => Time.now.to_i.to_s,
71
+ :status => text_status
72
+ }
85
73
 
86
- results.each do |name, value|
74
+ results.each do |name, value|
87
75
 
88
- # The unnnamed/default check doesn't contribute data.
89
- next if name.nil?
76
+ # The unnnamed/default check doesn't contribute data.
77
+ next if name.nil?
90
78
 
91
- if failure? value
79
+ if failure? value
92
80
 
93
- # If a check fails its name is added to a `failures` array.
94
- # If the check failed because it timed out, its name is
95
- # added to a `timeouts` array instead.
81
+ # If a check fails its name is added to a `failures` array.
82
+ # If the check failed because it timed out, its name is
83
+ # added to a `timeouts` array instead.
96
84
 
97
- key = timeout?(value) ? :timeouts : :failures
98
- (data[key] ||= []) << name
85
+ key = timeout?(value) ? :timeouts : :failures
86
+ (data[key] ||= []) << name
99
87
 
100
- elsif value
88
+ elsif value
101
89
 
102
- # If the check passed and returned a value, the stringified
103
- # version of the value is returned under the `name` key.
90
+ # If the check passed and returned a value, the stringified
91
+ # version of the value is returned under the `name` key.
104
92
 
105
- data[name] = value.to_s
93
+ data[name] = value.to_s
94
+ end
106
95
  end
107
- end
108
96
 
109
- [http_status, HEADERS, [JSON.generate(data)]]
110
- end
97
+ [http_status, HEADERS, [JSON.generate(data)]]
98
+ end
111
99
 
112
- rescue Exception => ex
100
+ rescue Exception => ex
113
101
 
114
- p :fuck => ex
115
- # Something catastrophic happened. We can't even run the checks
116
- # and render a JSON response. Fall back on a pre-rendered string
117
- # and interpolate the current epoch time.
102
+ # Something catastrophic happened. We can't even run the checks
103
+ # and render a JSON response. Fall back on a pre-rendered string
104
+ # and interpolate the current epoch time.
118
105
 
119
- now = Time.now.to_i.to_s
120
- [500, HEADERS, ['{"status":"fail","now":"' + now + '"}']]
106
+ now = Time.now.to_i.to_s
107
+ [500, HEADERS, ['{"status":"failures","now":"' + now + '"}']]
108
+ end
121
109
  end
122
110
 
123
111
  # Add a new check with optional `name`. A `:timeout` option can be
@@ -0,0 +1,21 @@
1
+ class Pinglish
2
+ class Check
3
+ attr_reader :group
4
+ attr_reader :name
5
+ attr_reader :timeout
6
+
7
+ def initialize(name, options = nil, &block)
8
+ options ||= {}
9
+ @group = options[:group]
10
+ @name = name
11
+ @timeout = options[:timeout] || 1
12
+ @block = block
13
+ end
14
+
15
+ # Call this check's behavior, returning the result of the block.
16
+
17
+ def call(*args, &block)
18
+ @block.call *args, &block
19
+ end
20
+ end
21
+ end
data/pinglish.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = "pinglish"
5
- gem.version = "0.0.1"
5
+ gem.version = "0.1.0"
6
6
  gem.authors = ["John Barnette", "Will Farrington"]
7
7
  gem.email = ["jbarnette@github.com", "wfarr@github.com"]
8
8
  gem.description = "A simple Rack middleware for checking app health."
data/script/bootstrap CHANGED
@@ -6,4 +6,4 @@ set -e
6
6
  cd $(dirname "$0")/..
7
7
  rm -rf .bundle/config
8
8
 
9
- bundle install --path .bundle --binstubs .bundle/binstubs --quiet
9
+ bundle install --path .bundle --binstubs .bundle/binstubs --quiet "$@"
File without changes
@@ -2,7 +2,7 @@ require "helper"
2
2
  require "rack/test"
3
3
 
4
4
  class PinglishTest < MiniTest::Unit::TestCase
5
- FakeApp = lambda { |env| [404, {}, []] }
5
+ FakeApp = lambda { |env| [200, {}, ["fake"]] }
6
6
 
7
7
  def build_app(*args, &block)
8
8
  Rack::Builder.new do |builder|
@@ -11,18 +11,40 @@ class PinglishTest < MiniTest::Unit::TestCase
11
11
  end
12
12
  end
13
13
 
14
+ def test_with_non_matching_request_path
15
+ app = build_app
16
+
17
+ session = Rack::Test::Session.new(app)
18
+ session.get "/something"
19
+ assert_equal 200, session.last_response.status
20
+ assert_equal "fake", session.last_response.body
21
+ end
22
+
23
+ def test_with_non_matching_request_path_and_exception
24
+ app = Rack::Builder.new do |builder|
25
+ builder.use Pinglish
26
+ builder.run lambda { |env| raise "boom" }
27
+ end
28
+
29
+ session = Rack::Test::Session.new(app)
30
+
31
+ assert_raises RuntimeError do
32
+ session.get "/something"
33
+ end
34
+ end
35
+
14
36
  def test_with_defaults
15
37
  app = build_app
16
38
 
17
39
  session = Rack::Test::Session.new(app)
18
- session.get '/_ping'
40
+ session.get "/_ping"
19
41
  assert_equal 200, session.last_response.status
20
- assert_equal 'application/json; charset=UTF-8',
42
+ assert_equal "application/json; charset=UTF-8",
21
43
  session.last_response.content_type
22
44
 
23
45
  json = JSON.load(session.last_response.body)
24
- assert json.key?('now')
25
- assert_equal 'ok', json['status']
46
+ assert json.key?("now")
47
+ assert_equal "ok", json["status"]
26
48
  end
27
49
 
28
50
  def test_with_good_check
@@ -32,16 +54,16 @@ class PinglishTest < MiniTest::Unit::TestCase
32
54
  end
33
55
 
34
56
  session = Rack::Test::Session.new(app)
35
- session.get '/_ping'
57
+ session.get "/_ping"
36
58
 
37
- assert_equal 'application/json; charset=UTF-8',
59
+ assert_equal "application/json; charset=UTF-8",
38
60
  session.last_response.content_type
39
61
 
40
62
  json = JSON.load(session.last_response.body)
41
- assert json.key?('now')
42
- assert_equal 'ok', json['status']
43
- assert_equal 'up_and_at_em', json['db']
44
- assert_equal 'pushin_and_poppin', json['queue']
63
+ assert json.key?("now")
64
+ assert_equal "ok", json["status"]
65
+ assert_equal "up_and_at_em", json["db"]
66
+ assert_equal "pushin_and_poppin", json["queue"]
45
67
  end
46
68
 
47
69
  def test_with_unnamed_check
@@ -50,32 +72,32 @@ class PinglishTest < MiniTest::Unit::TestCase
50
72
  end
51
73
 
52
74
  session = Rack::Test::Session.new(app)
53
- session.get '/_ping'
75
+ session.get "/_ping"
54
76
 
55
- assert_equal 'application/json; charset=UTF-8',
77
+ assert_equal "application/json; charset=UTF-8",
56
78
  session.last_response.content_type
57
79
 
58
80
  json = JSON.load(session.last_response.body)
59
- assert json.key?('now')
60
- assert_equal 'ok', json['status']
81
+ assert json.key?("now")
82
+ assert_equal "ok", json["status"]
61
83
  end
62
84
 
63
85
  def test_with_check_that_raises
64
86
  app = build_app do |ping|
65
87
  ping.check(:db) { :ok }
66
- ping.check(:raise) { raise 'nooooope' }
88
+ ping.check(:raise) { raise "nooooope" }
67
89
  end
68
90
 
69
91
  session = Rack::Test::Session.new(app)
70
- session.get '/_ping'
92
+ session.get "/_ping"
71
93
 
72
94
  assert_equal 503, session.last_response.status
73
- assert_equal 'application/json; charset=UTF-8',
95
+ assert_equal "application/json; charset=UTF-8",
74
96
  session.last_response.content_type
75
97
 
76
98
  json = JSON.load(session.last_response.body)
77
- assert json.key?('now')
78
- assert_equal 'fail', json['status']
99
+ assert json.key?("now")
100
+ assert_equal "failures", json["status"]
79
101
  end
80
102
 
81
103
  def test_with_check_that_returns_false
@@ -85,16 +107,16 @@ class PinglishTest < MiniTest::Unit::TestCase
85
107
  end
86
108
 
87
109
  session = Rack::Test::Session.new(app)
88
- session.get '/_ping'
110
+ session.get "/_ping"
89
111
 
90
112
  assert_equal 503, session.last_response.status
91
- assert_equal 'application/json; charset=UTF-8',
113
+ assert_equal "application/json; charset=UTF-8",
92
114
  session.last_response.content_type
93
115
 
94
116
  json = JSON.load(session.last_response.body)
95
- assert json.key?('now')
96
- assert_equal 'fail', json['status']
97
- assert_equal ['fail'], json['failures']
117
+ assert json.key?("now")
118
+ assert_equal "failures", json["status"]
119
+ assert_equal ["fail"], json["failures"]
98
120
  end
99
121
 
100
122
  def test_with_check_that_times_out
@@ -104,30 +126,30 @@ class PinglishTest < MiniTest::Unit::TestCase
104
126
  end
105
127
 
106
128
  session = Rack::Test::Session.new(app)
107
- session.get '/_ping'
129
+ session.get "/_ping"
108
130
 
109
131
  assert_equal 503, session.last_response.status
110
- assert_equal 'application/json; charset=UTF-8',
132
+ assert_equal "application/json; charset=UTF-8",
111
133
  session.last_response.content_type
112
134
 
113
135
  json = JSON.load(session.last_response.body)
114
- assert json.key?('now')
115
- assert_equal 'fail', json['status']
116
- assert_equal ['long'], json['timeouts']
136
+ assert json.key?("now")
137
+ assert_equal "failures", json["status"]
138
+ assert_equal ["long"], json["timeouts"]
117
139
  end
118
140
 
119
141
  def test_with_custom_path
120
- app = build_app("/_piiiiing")
142
+ app = build_app(:path => "/_piiiiing")
121
143
 
122
144
  session = Rack::Test::Session.new(app)
123
- session.get '/_piiiiing'
145
+ session.get "/_piiiiing"
124
146
  assert_equal 200, session.last_response.status
125
- assert_equal 'application/json; charset=UTF-8',
147
+ assert_equal "application/json; charset=UTF-8",
126
148
  session.last_response.content_type
127
149
 
128
150
  json = JSON.load(session.last_response.body)
129
- assert json.key?('now')
130
- assert_equal 'ok', json['status']
151
+ assert json.key?("now")
152
+ assert_equal "ok", json["status"]
131
153
  end
132
154
 
133
155
  def test_check_without_name
@@ -146,32 +168,25 @@ class PinglishTest < MiniTest::Unit::TestCase
146
168
  def test_failure_boolean
147
169
  pinglish = Pinglish.new(FakeApp)
148
170
 
149
- assert pinglish.failure?(Exception.new),
150
- "Expected failure with exception to be true"
171
+ assert pinglish.failure?(Exception.new)
172
+ assert pinglish.failure?(false)
151
173
 
152
- assert pinglish.failure?(false),
153
- "Expected failure with false to be true"
154
-
155
- assert !pinglish.failure?(true),
156
- "Expected failure with true value to be false"
157
-
158
- assert !pinglish.failure?(:ok),
159
- "Expected failure with non-false and non-exception to be false"
174
+ refute pinglish.failure?(true)
175
+ refute pinglish.failure?(:ok)
160
176
  end
161
177
 
162
178
  def test_timeout
163
179
  pinglish = Pinglish.new(FakeApp)
164
- begin
180
+
181
+ assert_raises Pinglish::TooLong do
165
182
  pinglish.timeout(0.001) { sleep 0.003 }
166
- assert false, "Timeout did not happen, but should have."
167
- rescue Pinglish::TooLong => e
168
- # all good
169
183
  end
170
184
  end
171
185
 
172
186
  def test_timeout_boolean
173
187
  pinglish = Pinglish.new(FakeApp)
174
- assert_equal true, pinglish.timeout?(Pinglish::TooLong.new)
175
- assert_equal false, pinglish.timeout?(Exception.new)
188
+
189
+ assert pinglish.timeout?(Pinglish::TooLong.new)
190
+ refute pinglish.timeout?(Exception.new)
176
191
  end
177
192
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pinglish
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-02-26 00:00:00.000000000 Z
13
+ date: 2013-04-18 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rack
@@ -70,14 +70,14 @@ extra_rdoc_files: []
70
70
  files:
71
71
  - .gitignore
72
72
  - Gemfile
73
- - Gemfile.lock
74
73
  - LICENSE
75
74
  - README.md
76
75
  - lib/pinglish.rb
76
+ - lib/pinglish/check.rb
77
77
  - pinglish.gemspec
78
78
  - script/bootstrap
79
79
  - script/release
80
- - script/tests
80
+ - script/test
81
81
  - test/check_test.rb
82
82
  - test/helper.rb
83
83
  - test/pinglish_test.rb
data/Gemfile.lock DELETED
@@ -1,21 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- pinglish (0.0.0)
5
- rack
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- minitest (4.5.0)
11
- rack (1.5.0)
12
- rack-test (0.6.2)
13
- rack (>= 1.0)
14
-
15
- PLATFORMS
16
- ruby
17
-
18
- DEPENDENCIES
19
- minitest (~> 4.5)
20
- pinglish!
21
- rack-test (~> 0.6)