rx-healthcheck 0.1.4 → 0.1.8

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: a275e460e929db3791b73f3acd52d036641d4128212ee4803dc9a16788d49ea4
4
- data.tar.gz: 0cebd0272eb7b8d03c443deec4f77a4e771f24c40e5536f01ff438af2d392a23
3
+ metadata.gz: 3ca68e3e5241e5baf4b9b2454ece5f8cc87889f018ac31dfdb8e2243d58107da
4
+ data.tar.gz: eda14ecb4304cb18e4b95f2f0431d23b14c119c1b95e25622711cf5aa193019a
5
5
  SHA512:
6
- metadata.gz: e47bfd076e689fd4f35f9b5f8f1e9e25545d9a89092628507f2d0bebf00fd594d12d797460015f4c94dd32df589100beca9ed3184966a9778480c73f24d52640
7
- data.tar.gz: 5f30e6b1da95f03200f0d0ab83e27cd48b1557a1446dccb5567490af7d951654b7294e31b4a622134e8fbd20e752c07836b4bdb1267775180cc03ffc462c5884
6
+ metadata.gz: f59ce880cd0cba664a0705b76393bdefa84a7b91e595c001b9d59bc0161be13b32d5736ffd57db204c495f2537045cc23932c0bebb51c13b94081664111fbd7b
7
+ data.tar.gz: d333264758d8233c45b397cda440528a24474a2000b0ddb9950dbf87feb81444c464015e1d7aa27f241efabec21b37b231518b57fb1f3fe0fc05fc53b6c8cb12
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/
@@ -26,4 +26,4 @@ DEPENDENCIES
26
26
  simplecov (= 0.21.2)
27
27
 
28
28
  BUNDLED WITH
29
- 2.2.11
29
+ 2.2.29
data/README.md CHANGED
@@ -59,14 +59,30 @@ 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
+ ### Deep end-point authorization
63
+
64
+ 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`:
65
+
66
+ ```ruby
67
+ options: {
68
+ #default
69
+ authorization: <token>
70
+
71
+ #custom
72
+ authorization: -> (env) {
73
+ #your code goes here
74
+ }
75
+ }
76
+ ```
77
+
62
78
  ## Contributing
63
79
 
64
80
  Bug reports and pull requests are welcome on GitHub at https://github.com/zachpendleton/rx.
65
81
 
66
82
  Some tips for developing the gem locally:
67
83
 
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).
84
+ - Tests can be run by calling `rake`
85
+ - 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
86
 
71
87
  ## License
72
88
 
@@ -3,17 +3,20 @@ module Rx
3
3
  class FileSystemCheck
4
4
  FILENAME = "rx".freeze
5
5
 
6
- attr_reader :name
6
+ attr_reader :name, :timeout
7
7
 
8
- def initialize(name = "fs")
8
+ def initialize(name = "fs", timeout = 0)
9
9
  @name = name
10
+ @timeout = 0
10
11
  end
11
12
 
12
13
  def check
13
14
  Result.from(name) do
14
- !!Tempfile.open(FILENAME) do |f|
15
- f.write("ok")
16
- f.flush
15
+ Timeout::timeout(timeout) do
16
+ !!Tempfile.open(FILENAME) do |f|
17
+ f.write("ok")
18
+ f.flush
19
+ end
17
20
  end
18
21
  end
19
22
  end
@@ -1,16 +1,19 @@
1
+ require "timeout"
2
+
1
3
  module Rx
2
4
  module Check
3
5
  class GenericCheck
4
- attr_reader :name
6
+ attr_reader :name, :timeout
5
7
 
6
- def initialize(callable, name = "generic")
8
+ def initialize(callable, name = "generic", timeout = 0)
7
9
  @callable = callable
8
10
  @name = name
11
+ @timeout = timeout
9
12
  end
10
13
 
11
14
  def check
12
15
  Result.from(name) do
13
- callable.call
16
+ Timeout::timeout(timeout) { callable.call }
14
17
  end
15
18
  end
16
19
 
@@ -3,17 +3,18 @@ require "uri"
3
3
  module Rx
4
4
  module Check
5
5
  class HttpCheck
6
- attr_reader :name
6
+ attr_reader :name, :timeout
7
7
 
8
- def initialize(url, name = "http")
8
+ def initialize(url, name = "http", timeout: 1)
9
9
  @url = URI(url)
10
10
  @name = name
11
+ @timeout = timeout
11
12
  end
12
13
 
13
14
  def check
14
15
  Result.from(name) do
15
16
  http = Net::HTTP.new(url.host, url.port)
16
- http.read_timeout = 1
17
+ http.read_timeout = timeout
17
18
  http.use_ssl = url.scheme == "https"
18
19
 
19
20
  response = http.request(Net::HTTP::Get.new(path))
@@ -14,6 +14,10 @@ module Rx
14
14
  Future.new(&block).execute
15
15
  end
16
16
 
17
+ def self.thread_pool
18
+ @@pool
19
+ end
20
+
17
21
  def initialize(&block)
18
22
  @channel = Queue.new
19
23
  @state = :pending
@@ -28,7 +32,7 @@ module Rx
28
32
  @state = :in_progress
29
33
  pool.submit do
30
34
  begin
31
- channel << work.call
35
+ channel << execute_work(&work)
32
36
  @state = :completed
33
37
  rescue StandardError => ex
34
38
  @error = ex
@@ -66,6 +70,10 @@ module Rx
66
70
  def pool
67
71
  @@pool
68
72
  end
73
+
74
+ def execute_work(&block)
75
+ defined?(Rails) ? Rails.application.executor.wrap(&block) : block.call
76
+ end
69
77
  end
70
78
  end
71
79
  end
@@ -6,6 +6,7 @@ module Rx
6
6
  def initialize(size = Etc.nprocessors)
7
7
  @pool = []
8
8
  @size = size
9
+ @pid = Process.pid
9
10
  end
10
11
 
11
12
  def shutdown
@@ -25,17 +26,33 @@ module Rx
25
26
  self
26
27
  end
27
28
 
29
+ def restart
30
+ shutdown
31
+ start
32
+ end
33
+
28
34
  def started?
29
35
  pool.map(&:alive?).any?
30
36
  end
31
37
 
32
38
  def submit(&block)
39
+ restart_on_fork if forked?
40
+
33
41
  return unless started?
34
42
  queue << block
35
43
  end
36
44
 
37
45
  private
38
- attr_reader :pool, :queue, :size
46
+ attr_reader :pid, :pool, :queue, :size
47
+
48
+ def forked?
49
+ Process.pid != pid
50
+ end
51
+
52
+ def restart_on_fork
53
+ restart
54
+ @pid = Process.pid
55
+ end
39
56
 
40
57
  def worker
41
58
  -> {
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
@@ -79,6 +84,14 @@ module Rx
79
84
  ]
80
85
  end
81
86
 
87
+ def deep_response_authorization_failed
88
+ [
89
+ 403,
90
+ {"content-type" => "application/json"},
91
+ [JSON.dump({ message: "authorization failed" })]
92
+ ]
93
+ end
94
+
82
95
  def deep_response(readiness, critical, secondary)
83
96
  status = (readiness.map { |x| x[:status] == 200 } + critical.map { |x| x[:status] == 200 }).all? ? 200 : 503
84
97
 
@@ -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.4"
4
+ VERSION = "0.1.8"
5
5
  end
data/lib/rx.rb CHANGED
@@ -12,6 +12,7 @@ require_relative "rx/check/result"
12
12
  require_relative "rx/concurrent/future"
13
13
  require_relative "rx/concurrent/thread_pool"
14
14
  require_relative "rx/util/heap"
15
+ require_relative "rx/util/health_check_authorization"
15
16
 
16
17
  module Rx
17
18
  class Error < StandardError; end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rx-healthcheck
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Pendleton
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-07 00:00:00.000000000 Z
11
+ date: 2022-01-31 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description:
13
+ description:
14
14
  email:
15
15
  - zachpendleton@gmail.com
16
16
  executables: []
@@ -36,6 +36,7 @@ files:
36
36
  - lib/rx/concurrent/future.rb
37
37
  - lib/rx/concurrent/thread_pool.rb
38
38
  - lib/rx/middleware.rb
39
+ - lib/rx/util/health_check_authorization.rb
39
40
  - lib/rx/util/heap.rb
40
41
  - lib/rx/version.rb
41
42
  - rx.gemspec
@@ -45,7 +46,7 @@ licenses:
45
46
  metadata:
46
47
  homepage_uri: https://github.com/zachpendleton/rx
47
48
  source_code_uri: https://github.com/zachpendleton/rx
48
- post_install_message:
49
+ post_install_message:
49
50
  rdoc_options: []
50
51
  require_paths:
51
52
  - lib
@@ -60,8 +61,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
61
  - !ruby/object:Gem::Version
61
62
  version: '0'
62
63
  requirements: []
63
- rubygems_version: 3.1.2
64
- signing_key:
64
+ rubygems_version: 3.2.22
65
+ signing_key:
65
66
  specification_version: 4
66
67
  summary: Standard health checks for Rails and Rack applications
67
68
  test_files: []