pinglish 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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)