rx-healthcheck 0.1.6 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a5089cc2aca4dab181a11a5aa9a3135862d7de57976ded482366a9e147ac7a8
4
- data.tar.gz: 4ec642b3e93f6b0f983cb7dff58b4bed8ede3e64dd7655bd1cac7f76583c7dfe
3
+ metadata.gz: ebf9af8d3b43d1640503ddcba7138d1ef6c04f298faa09b39c8d93fcb0d4eb50
4
+ data.tar.gz: e22f89c795207f5a3a78bb6f63c362624e6b4104e3834f6ca928ecb1c6fd5b79
5
5
  SHA512:
6
- metadata.gz: 439bc089d1ce63f1c63f687cdf0b8b473bbcb2f6bbf3c04a847905d176cdb667e6f6c3b6e754121af685b87fc2b00f318ca3e4c6fc2de17fd80cd4cd88693ff2
7
- data.tar.gz: 37c97bcd6967d3d336e669d78b6474978771c0d7dbc79daca8276dd66484c2485398f1cc6bd888c5f46f63e4855c33c9b4bb70a7b7e042937b588259e7b61a0f
6
+ metadata.gz: a194f56c544904474062a866aa7c91cfe6de9548b97802beaa448b4b082dab4c1fc3ffa7f41e3c0aa14b8f94c11d518e586d6984f1a82cbfaf0d2479abc9ce06
7
+ data.tar.gz: 1fc1ea21c9586cb3583d25ab7c8ab7177d0789ec085cc4de316dd136ebeb3c03872f30c2b54293c2efd254ea5ebae6d0255d86816488020a584e7c1b8c8b39f9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rx-healthcheck (0.1.4)
4
+ rx-healthcheck (0.1.8)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -17,6 +17,7 @@ GEM
17
17
  simplecov_json_formatter (0.1.3)
18
18
 
19
19
  PLATFORMS
20
+ ruby
20
21
  x86_64-linux
21
22
 
22
23
  DEPENDENCIES
@@ -26,4 +27,4 @@ DEPENDENCIES
26
27
  simplecov (= 0.21.2)
27
28
 
28
29
  BUNDLED WITH
29
- 2.2.11
30
+ 2.2.29
data/README.md CHANGED
@@ -59,14 +59,52 @@ deep_secondary: []
59
59
 
60
60
  Each collection must contain 0 or more `Rx::Check` objects. Those checks will be performed when the health check is queried. Deep checks will always also run the readiness checks.
61
61
 
62
+ ### Cache
63
+
64
+ For deep health checks Rx by default will use an in-memory cache. While this is useful when running in production, during testing it could lead to unexpected results.
65
+ You can disable the in-memory cache by setting the cache key false in the options hash.
66
+
67
+ ```ruby
68
+ Rails.application.config.middleware.insert(
69
+ Rx::Middleware,
70
+ liveness: [Rx::Check::FileSystemCheck.new],
71
+ readiness: [
72
+ Rx::Check::FileSystemCheck.new,
73
+ Rx::Check::ActiveRecordCheck.new,
74
+ Rx::Check::HttpCheck.new("http://example.com"),
75
+ Rx::Check::GenericCheck.new(-> { $redis.ping == "PONG" }, "redis")],
76
+ deep_critical: [Rx::Check::HttpCheck.new("http://criticalservice.com/health")],
77
+ deep_secondary: [Rx::Check::HttpCheck.new("http://otherservice.com/health-check")],
78
+ options: {
79
+ cache: false
80
+ }
81
+ )
82
+ ```
83
+
84
+ ### Deep end-point authorization
85
+
86
+ It is considered as a good practice to protect the deep checks with a GUID to mitigate DDOS attacks. Hence you have 2 options to enable this. One is to use the `default_authorization` by passing the token to the authorization inside options hash, which you can use in a request with the authorization_token in the header of it. The other option would be to pass a lambda with an env argument (this gives you access to hash of request data) and have your own `custom_authorization`:
87
+
88
+ ```ruby
89
+ options: {
90
+ #default
91
+ authorization: <token>
92
+
93
+ #custom
94
+ authorization: -> (env) {
95
+ #your code goes here
96
+ }
97
+ }
98
+ ```
99
+
62
100
  ## Contributing
63
101
 
64
102
  Bug reports and pull requests are welcome on GitHub at https://github.com/zachpendleton/rx.
65
103
 
66
104
  Some tips for developing the gem locally:
67
105
 
68
- * Tests can be run by calling `rake`
69
- * You can point your Rails app to a local gem by adding a `path` option to your Gemfile, a la `gem "rx", path: "path/to/rx" (though you _will_ need to restart Rails whenever you change the gem).
106
+ - Tests can be run by calling `rake`
107
+ - You can point your Rails app to a local gem by adding a `path` option to your Gemfile, a la `gem "rx", path: "path/to/rx" (though you _will_ need to restart Rails whenever you change the gem).
70
108
 
71
109
  ## License
72
110
 
@@ -2,7 +2,7 @@ require_relative "../util/heap"
2
2
 
3
3
  module Rx
4
4
  module Cache
5
- class InMemoryCache
5
+ class LRUCache
6
6
  def initialize
7
7
  @heap = Rx::Util::Heap.new do |a, b|
8
8
  a[1] < b[1]
@@ -0,0 +1,45 @@
1
+ require "thread"
2
+
3
+ module Rx
4
+ module Cache
5
+ class MapCache
6
+ def initialize
7
+ @data = {}
8
+ @lock = Mutex.new
9
+ end
10
+
11
+ def cache(k, expires_in = 60)
12
+ unless (value = get(k)).nil?
13
+ return value
14
+ end
15
+
16
+ value = yield
17
+ put(k, value, expires_in)
18
+ value
19
+ end
20
+
21
+ def get(k)
22
+ lock.synchronize do
23
+ value = data[k]
24
+ return nil unless value
25
+
26
+ if value[1] < Time.now
27
+ data.delete(k)
28
+ return nil
29
+ end
30
+
31
+ value[0]
32
+ end
33
+ end
34
+
35
+ def put(k, v, expires_in = 60)
36
+ lock.synchronize do
37
+ data[k] = [v, Time.now + expires_in]
38
+ end
39
+ end
40
+
41
+ private
42
+ attr_reader :data, :lock
43
+ end
44
+ end
45
+ end
@@ -32,7 +32,7 @@ module Rx
32
32
  @state = :in_progress
33
33
  pool.submit do
34
34
  begin
35
- channel << work.call
35
+ channel << execute_work(&work)
36
36
  @state = :completed
37
37
  rescue StandardError => ex
38
38
  @error = ex
@@ -70,6 +70,10 @@ module Rx
70
70
  def pool
71
71
  @@pool
72
72
  end
73
+
74
+ def execute_work(&block)
75
+ defined?(Rails) ? Rails.application.executor.wrap(&block) : block.call
76
+ end
73
77
  end
74
78
  end
75
79
  end
data/lib/rx/middleware.rb CHANGED
@@ -3,7 +3,8 @@ require "json"
3
3
  module Rx
4
4
  class Middleware
5
5
  DEFAULT_OPTIONS = {
6
- cache: true
6
+ cache: true,
7
+ authorization: nil
7
8
  }.freeze
8
9
 
9
10
  def initialize(app,
@@ -34,12 +35,16 @@ module Rx
34
35
  when "/readiness"
35
36
  readiness_response(check_to_component(readiness_checks))
36
37
  when "/deep"
37
- @cache.cache("deep") do
38
- readiness = check_to_component(readiness_checks)
39
- critical = check_to_component(deep_critical_checks)
40
- secondary = check_to_component(deep_secondary_checks)
41
-
42
- deep_response(readiness, critical, secondary)
38
+ if !Rx::Util::HealthCheckAuthorization.new(env, @options[:authorization]).ok?
39
+ deep_response_authorization_failed
40
+ else
41
+ @cache.cache("deep") do
42
+ readiness = check_to_component(readiness_checks)
43
+ critical = check_to_component(deep_critical_checks)
44
+ secondary = check_to_component(deep_secondary_checks)
45
+
46
+ deep_response(readiness, critical, secondary)
47
+ end
43
48
  end
44
49
  end
45
50
  end
@@ -50,11 +55,16 @@ module Rx
50
55
  :deep_secondary_checks, :options
51
56
 
52
57
  def cache_factory(options)
53
- unless options[:cache]
54
- return Rx::Cache::NoOpCache.new
58
+ case options[:cache]
59
+ when true
60
+ Rx::Cache::LRUCache.new
61
+ when "LRU"
62
+ Rx::Cache::LRUCache.new
63
+ when "MAP"
64
+ Rx::Cache::MapCache.new
65
+ else
66
+ Rx::Cache::NoOpCache.new
55
67
  end
56
-
57
- Rx::Cache::InMemoryCache.new
58
68
  end
59
69
 
60
70
  def health_check_request?(path)
@@ -79,6 +89,14 @@ module Rx
79
89
  ]
80
90
  end
81
91
 
92
+ def deep_response_authorization_failed
93
+ [
94
+ 403,
95
+ {"content-type" => "application/json"},
96
+ [JSON.dump({ message: "authorization failed" })]
97
+ ]
98
+ end
99
+
82
100
  def deep_response(readiness, critical, secondary)
83
101
  status = (readiness.map { |x| x[:status] == 200 } + critical.map { |x| x[:status] == 200 }).all? ? 200 : 503
84
102
 
@@ -0,0 +1,25 @@
1
+ module Rx
2
+ module Util
3
+ class HealthCheckAuthorization
4
+ HTTP_HEADER = "HTTP_AUTHORIZATION"
5
+
6
+ def initialize(env, authorization)
7
+ @authorization = authorization
8
+ @env = env
9
+ end
10
+
11
+ def ok?
12
+ case @authorization
13
+ when NilClass
14
+ true
15
+ when Proc
16
+ @authorization.call(@env)
17
+ when String
18
+ @authorization == @env[HTTP_HEADER]
19
+ else
20
+ raise StandardError.new("Authorization is not configured properly")
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
data/lib/rx/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rx
4
- VERSION = "0.1.6"
4
+ VERSION = "0.1.9"
5
5
  end
data/lib/rx.rb CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  require_relative "rx/version"
4
4
  require_relative "rx/middleware"
5
- require_relative "rx/cache/in_memory_cache"
5
+ require_relative "rx/cache/lru_cache"
6
+ require_relative "rx/cache/map_cache"
6
7
  require_relative "rx/cache/no_op_cache"
7
8
  require_relative "rx/check/active_record_check"
8
9
  require_relative "rx/check/file_system_check"
@@ -12,6 +13,7 @@ require_relative "rx/check/result"
12
13
  require_relative "rx/concurrent/future"
13
14
  require_relative "rx/concurrent/thread_pool"
14
15
  require_relative "rx/util/heap"
16
+ require_relative "rx/util/health_check_authorization"
15
17
 
16
18
  module Rx
17
19
  class Error < StandardError; end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rx-healthcheck
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Pendleton
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-29 00:00:00.000000000 Z
11
+ date: 2022-04-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -26,7 +26,8 @@ files:
26
26
  - bin/console
27
27
  - bin/setup
28
28
  - lib/rx.rb
29
- - lib/rx/cache/in_memory_cache.rb
29
+ - lib/rx/cache/lru_cache.rb
30
+ - lib/rx/cache/map_cache.rb
30
31
  - lib/rx/cache/no_op_cache.rb
31
32
  - lib/rx/check/active_record_check.rb
32
33
  - lib/rx/check/file_system_check.rb
@@ -36,6 +37,7 @@ files:
36
37
  - lib/rx/concurrent/future.rb
37
38
  - lib/rx/concurrent/thread_pool.rb
38
39
  - lib/rx/middleware.rb
40
+ - lib/rx/util/health_check_authorization.rb
39
41
  - lib/rx/util/heap.rb
40
42
  - lib/rx/version.rb
41
43
  - rx.gemspec