rx-healthcheck 0.1.6 → 0.1.9

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 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