health-reporter 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +1 -0
- data/health-reporter.gemspec +1 -0
- data/lib/health_reporter.rb +1 -1
- data/lib/health_reporter/reporter.rb +67 -8
- data/lib/health_reporter/version.rb +2 -2
- data/spec/reporter.rb +190 -3
- data/spec/spec_helper.rb +26 -1
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90f655ef277bd77b6f90e6129976868c5c3f934f
|
4
|
+
data.tar.gz: d905978f2768c0472a238e4b5c8c3c0b3831e882
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ab4e6974bcc5ffad2e8d454e28f21e87d1528c6bd3fbfc4fd13bdcd1850d57a0502df6e7000b9d2fa3d21fa0eabfcca69564b0495f2972f25d256aa8262fd0d
|
7
|
+
data.tar.gz: df47ccab910847e661cc3769594344408635bdced26e8c93563bfceb672fa6445ad332010ae94dc05cf0ede58be9fb7bcf80fec1cd13b8afb28a77eae4e935ac
|
data/.gitignore
CHANGED
data/README.md
CHANGED
data/health-reporter.gemspec
CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
+
spec.add_development_dependency 'timecop', '~> 0.8.0'
|
22
23
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
23
24
|
spec.add_development_dependency 'rake', '~> 10.0'
|
24
25
|
spec.add_development_dependency 'rspec', '~> 2.13'
|
data/lib/health_reporter.rb
CHANGED
@@ -1,15 +1,74 @@
|
|
1
|
-
require '
|
1
|
+
require 'singleton'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
class HealthReporter
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
def self.self_test
|
7
|
+
@@self_test
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.self_test=(self_test)
|
11
|
+
@@self_test = self_test
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.unhealthy_cache_ttl
|
15
|
+
@@unhealthy_cache_ttl
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.unhealthy_cache_ttl=(unhealthy_cache_ttl)
|
19
|
+
@@unhealthy_cache_ttl = unhealthy_cache_ttl
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.healthy_cache_ttl
|
23
|
+
@@healthy_cache_ttl
|
24
|
+
end
|
8
25
|
|
26
|
+
def self.healthy_cache_ttl=(healthy_cache_ttl)
|
27
|
+
@@healthy_cache_ttl = healthy_cache_ttl
|
28
|
+
end
|
29
|
+
|
30
|
+
@@self_test = lambda{ true }
|
31
|
+
@@unhealthy_cache_ttl = 30
|
32
|
+
@@healthy_cache_ttl = 60
|
33
|
+
@@last_check_time = nil
|
34
|
+
@@healthy = nil #Initialized as nil so that first call will set it
|
35
|
+
@@semaphore = Mutex.new
|
36
|
+
|
37
|
+
# TODO
|
38
|
+
# def register_dependency_check(url:, code: 200)
|
39
|
+
# raise "Configured URL #{url} is invalid" unless url =~ URI::regexp
|
40
|
+
#
|
41
|
+
# dependencies[]
|
42
|
+
# end
|
9
43
|
|
44
|
+
def self.healthy?
|
45
|
+
@@semaphore.synchronize {
|
46
|
+
perform_health_check if @@healthy.nil? or cache_ttl_expired
|
47
|
+
@@healthy
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
10
52
|
|
11
|
-
|
12
|
-
|
53
|
+
def self.perform_health_check
|
54
|
+
@@healthy = sanitize(@@self_test.call)
|
55
|
+
@@last_check_time = Time.now
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.sanitize(result)
|
59
|
+
unless [true, false].include?(result)
|
60
|
+
raise "Invalid non-boolean response from registered self-check lambda: #{result.to_s}"
|
13
61
|
end
|
62
|
+
result
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.cache_ttl_expired
|
66
|
+
return true if @@last_check_time.nil?
|
67
|
+
Time.now > (@@last_check_time + ttl)
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.ttl
|
71
|
+
return @@healthy_cache_ttl if @@healthy
|
72
|
+
@@unhealthy_cache_ttl
|
14
73
|
end
|
15
74
|
end
|
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = '0.0.
|
1
|
+
class HealthReporter
|
2
|
+
VERSION = '0.0.2'
|
3
3
|
end
|
data/spec/reporter.rb
CHANGED
@@ -1,12 +1,199 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'yaml'
|
3
2
|
|
4
|
-
describe HealthReporter
|
5
|
-
subject { HealthReporter
|
3
|
+
describe HealthReporter do
|
4
|
+
subject { HealthReporter }
|
6
5
|
|
7
6
|
it 'has a version number' do
|
8
7
|
expect(HealthReporter::VERSION).not_to be nil
|
9
8
|
end
|
10
9
|
|
10
|
+
before(:each) do
|
11
|
+
subject.healthy_cache_ttl = 60
|
12
|
+
subject.unhealthy_cache_ttl = 30
|
13
|
+
subject.self_test = lambda{ true }
|
14
|
+
subject.class_variable_set(:@@last_check_time, nil)
|
15
|
+
subject.class_variable_set(:@@healthy, nil)
|
16
|
+
Timecop.return
|
17
|
+
reset_lambda_runner_spy
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when configuring' do
|
21
|
+
it 'remembers the self-test lambda passed to it' do
|
22
|
+
test_lambda = lambda{ 'ab' == 'cd' }
|
23
|
+
subject.self_test = test_lambda
|
24
|
+
expect(subject.self_test).to be test_lambda
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'uses the self-test lambda passed to it' do
|
28
|
+
test_lambda = spy_lambda_returning_false
|
29
|
+
subject.self_test = test_lambda
|
30
|
+
expect(subject.self_test).to be test_lambda
|
31
|
+
expect(subject.healthy?).to be false
|
32
|
+
expect(spy_lambda_was_run?).to eq true
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'remembers the cache ttl when healthy' do
|
36
|
+
subject.healthy_cache_ttl = 10
|
37
|
+
expect(subject.healthy_cache_ttl).to eq 10
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'remembers the cache ttl when not healthy' do
|
41
|
+
subject.unhealthy_cache_ttl = 5
|
42
|
+
expect(subject.unhealthy_cache_ttl).to eq 5
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when exercising self-test lambda' do
|
47
|
+
it 'allows true to be returned by self-test lambda' do
|
48
|
+
test_lambda = lambda{ true }
|
49
|
+
subject.self_test = test_lambda
|
50
|
+
expect(subject.healthy?).to be true
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'allows false to be returned by self-test lambda' do
|
54
|
+
test_lambda = lambda{ false }
|
55
|
+
subject.self_test = test_lambda
|
56
|
+
expect(subject.healthy?).to be false
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'raises an exception when non-boolean values are returned by self-test lambda' do
|
60
|
+
test_lambda = lambda{ "I don't feel well..." }
|
61
|
+
subject.self_test = test_lambda
|
62
|
+
expect{subject.healthy?}.to raise_error RuntimeError, "Invalid non-boolean response from registered self-check lambda: I don't feel well..."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when initialized without any parameters' do
|
67
|
+
it 'sets the default self-test lambda to { true }' do
|
68
|
+
expect(subject.healthy?).to eq true
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'sets the default healthy state cache ttl to 60 seconds' do
|
72
|
+
expect(subject.healthy_cache_ttl).to eq 60
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'sets the default unhealthy state cache ttl to 30 seconds' do
|
76
|
+
expect(subject.unhealthy_cache_ttl).to eq 30
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when calling health check for first time (no cached health state)' do
|
81
|
+
it 'calls the configured self-test lambda and returns health' do
|
82
|
+
subject.self_test = spy_lambda_returning_false
|
83
|
+
expect(subject.healthy?).to be false
|
84
|
+
expect(spy_lambda_was_run?).to eq true
|
85
|
+
end
|
86
|
+
end
|
11
87
|
|
88
|
+
context 'when current state is healty' do
|
89
|
+
before(:each) do
|
90
|
+
subject.self_test = spy_lambda_returning_true
|
91
|
+
subject.healthy? #force the self-test
|
92
|
+
reset_lambda_runner_spy #reset the spy so that we can see if it was run or not
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'when neither healty-cache-ttl nor unhealty-cache-ttl has expired' do
|
96
|
+
before(:each) do
|
97
|
+
subject.unhealthy_cache_ttl = 10
|
98
|
+
subject.healthy_cache_ttl = 10
|
99
|
+
Timecop.freeze(Time.now + 5)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'does not call the registered self-test lambda' do
|
103
|
+
subject.healthy? #request here and test if it was run in expect below
|
104
|
+
expect(spy_lambda_was_run?).to eq false
|
105
|
+
end
|
106
|
+
it 'returns the current healthy state' do
|
107
|
+
expect(subject.healthy?).to be true
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'when healty-cache-ttl has expired' do
|
112
|
+
before do
|
113
|
+
subject.unhealthy_cache_ttl = 10
|
114
|
+
subject.healthy_cache_ttl = 3
|
115
|
+
Timecop.freeze(Time.now + 5)
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'calls the registered self-test lambda' do
|
119
|
+
subject.healthy? #request here and test if it was run in expect below
|
120
|
+
expect(spy_lambda_was_run?).to eq true
|
121
|
+
end
|
122
|
+
it 'returns the current healthy state' do
|
123
|
+
expect(subject.healthy?).to be true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'when unhealty-cache-ttl has expired' do
|
128
|
+
before(:each) do
|
129
|
+
subject.unhealthy_cache_ttl = 3
|
130
|
+
subject.healthy_cache_ttl = 10
|
131
|
+
Timecop.freeze(Time.now + 5)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'does not call the registered self-test lambda' do
|
135
|
+
subject.healthy? #request here and test if it was run in expect below
|
136
|
+
expect(spy_lambda_was_run?).to eq false
|
137
|
+
end
|
138
|
+
it 'returns the current healthy state' do
|
139
|
+
expect(subject.healthy?).to be true
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'when current state is unhealty' do
|
145
|
+
before(:each) do
|
146
|
+
subject.self_test = spy_lambda_returning_false
|
147
|
+
subject.healthy? #force the self-test
|
148
|
+
reset_lambda_runner_spy #reset the spy so that we can see if it was run or not
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'when neither healty-cache-ttl nor unhealty-cache-ttl has expired' do
|
152
|
+
before(:each) do
|
153
|
+
subject.unhealthy_cache_ttl = 10
|
154
|
+
subject.healthy_cache_ttl = 10
|
155
|
+
Timecop.freeze(Time.now + 5)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'does not call the registered self-test lambda' do
|
159
|
+
subject.healthy? #request here and test if it was run in expect below
|
160
|
+
expect(spy_lambda_was_run?).to eq false
|
161
|
+
end
|
162
|
+
it 'returns the current unhealthy state' do
|
163
|
+
expect(subject.healthy?).to be false
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'when healty-cache-ttl has expired' do
|
168
|
+
before(:each) do
|
169
|
+
subject.unhealthy_cache_ttl = 10
|
170
|
+
subject.healthy_cache_ttl = 3
|
171
|
+
Timecop.freeze(Time.now + 5)
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'does not call the registered self-test lambda' do
|
175
|
+
subject.healthy? #request here and test if it was run in expect below
|
176
|
+
expect(spy_lambda_was_run?).to eq false
|
177
|
+
end
|
178
|
+
it 'returns the current unhealthy state' do
|
179
|
+
expect(subject.healthy?).to be false
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context 'when unhealty-cache-ttl has expired' do
|
184
|
+
before(:each) do
|
185
|
+
subject.unhealthy_cache_ttl = 3
|
186
|
+
subject.healthy_cache_ttl = 10
|
187
|
+
Timecop.freeze(Time.now + 5)
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'calls the registered self-test lambda' do
|
191
|
+
subject.healthy? #request here and test if it was run in expect below
|
192
|
+
expect(spy_lambda_was_run?).to eq true
|
193
|
+
end
|
194
|
+
it 'returns the current unhealthy state' do
|
195
|
+
expect(subject.healthy?).to be false
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
12
199
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,11 +1,36 @@
|
|
1
1
|
require 'simplecov'
|
2
2
|
require 'simplecov-rcov'
|
3
|
+
require 'timecop'
|
3
4
|
|
4
5
|
SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
|
5
6
|
SimpleCov.start do
|
6
|
-
add_filter "
|
7
|
+
add_filter "./spec/"
|
7
8
|
end
|
8
9
|
|
9
10
|
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
10
11
|
|
11
12
|
require 'health_reporter'
|
13
|
+
|
14
|
+
|
15
|
+
def reset_lambda_runner_spy
|
16
|
+
@test_variable_from_sender = Random.new.rand(1...100000000000)
|
17
|
+
@test_variable_from_receiver = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def spy_lambda_was_run?
|
21
|
+
@test_variable_from_receiver == @test_variable_from_sender
|
22
|
+
end
|
23
|
+
|
24
|
+
def spy_lambda_returning_false
|
25
|
+
lambda{
|
26
|
+
@test_variable_from_receiver = @test_variable_from_sender
|
27
|
+
return false
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def spy_lambda_returning_true
|
32
|
+
lambda{
|
33
|
+
@test_variable_from_receiver = @test_variable_from_sender
|
34
|
+
return true
|
35
|
+
}
|
36
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: health-reporter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Barney de Villiers
|
@@ -10,6 +10,20 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2018-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: timecop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.8.0
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.8.0
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|