health-reporter 0.0.1 → 0.0.2
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/.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
|