middleware_healthcheck 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 38b91fef5d4a3905b2813f39042c793f360204d0b9c628f4f924d659ff192a2d
4
+ data.tar.gz: e147717615b025caeea300ad09aaf6d340018b28a740f61cd818a7f38e7fdfd1
5
+ SHA512:
6
+ metadata.gz: bffd5928ca999c46a20c7d6af18302899818b0b91aad1e6a2d5040bb02c28bb3d94d191febdf20376e820407b3785d22d03b63177275c1614c7265d8bdff5f24
7
+ data.tar.gz: b5798095104d400611081987408e5e4b19f1f2f4c3f13de21ab010c71d0746fe20d77497f434562d7280fec3adc449ae03d2ff4839a1302a36db7d34093480cc
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017 Adam Wieczorkowski
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # MiddlewareHealthcheck
2
+
3
+ ## Installation
4
+ Add this line to your application's Gemfile:
5
+ ```ruby
6
+ gem 'middleware_healthcheck'
7
+ ```
8
+
9
+ And then execute:
10
+ ```bash
11
+ $ bundle
12
+ ```
13
+
14
+ Or install it yourself as:
15
+ ```bash
16
+ $ gem install middleware_healthcheck
17
+ ```
18
+
19
+ ## Usage
20
+ Run basic check (without running any advanced checkers):
21
+ ```
22
+ /healthcheck
23
+ ```
24
+
25
+ To run all available checkers, add `full` parameter:
26
+ ```
27
+ /healthcheck?full=1
28
+ ```
29
+
30
+ To run selected checkers, add `checks` parameter, where the value is the name of checkers separated by a comma:
31
+ ```
32
+ /healthcheck?checks=active_record,second_checker,another_checker
33
+ ```
34
+
35
+ To change default path and parameters see Configuration section
36
+
37
+ ## Configuration
38
+ Create ``config/initializers/middleware_healthcheck.rb`` file
39
+ ```ruby
40
+ MiddlewareHealthcheck.configure do |config|
41
+ config.healthcheck_path = "my_custom_path"
42
+ ...
43
+ end
44
+ ```
45
+ Available options:
46
+ ```
47
+ healthcheck_path
48
+ full_check_param_name
49
+ selected_check_param_name
50
+ error_response_status
51
+ success_response_status
52
+ success_response_body
53
+ errors_delimiter
54
+ selected_check_param_split_delimiter
55
+ ```
56
+
57
+ ## Custom Checkers
58
+ Your Custom Checker class should look like this:
59
+ ```ruby
60
+ class MyCustomChecker
61
+ attr_accessor :error
62
+
63
+ def initialize(_app, _env)
64
+ end
65
+
66
+ def healthy?
67
+ if everything_ok?
68
+ true
69
+ else
70
+ self.error = 'Error message'
71
+ false
72
+ end
73
+ end
74
+ end
75
+ ```
76
+
77
+ To include Custom Checker, just add
78
+ ```ruby
79
+ HealthcheckMiddleware.configure do |config|
80
+ config.checkers << MyCustomChecker
81
+ end
82
+ ```
83
+ in initializer.
84
+
85
+ ## Development
86
+
87
+ ```
88
+ # build the docker containers
89
+ docker-compose build
90
+
91
+ # run the specs
92
+ docker-compose run --rm app bundle exec rspec
93
+
94
+ ```
95
+
96
+ ## License
97
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'MiddlewareHealthcheck'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+
21
+
22
+ require 'bundler/gem_tasks'
23
+
@@ -0,0 +1,19 @@
1
+ require "middleware_healthcheck/rails" if defined? Rails::Railtie
2
+ require "middleware_healthcheck/default_checkers"
3
+ require "middleware_healthcheck/configuration"
4
+ require "middleware_healthcheck/main_checker"
5
+ require "middleware_healthcheck/middleware"
6
+
7
+ module MiddlewareHealthcheck
8
+ class << self
9
+ attr_accessor :configuration
10
+
11
+ def configuration
12
+ @configuration ||= Configuration.new
13
+ end
14
+
15
+ def configure
16
+ yield configuration
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ module MiddlewareHealthcheck
2
+ class Configuration
3
+ DEFAULT_HEALTHCHECK_PATH = '/healthcheck'.freeze
4
+ DEFAULT_FULL_CHECK_PARAM_NAME = 'full'.freeze
5
+ DEFAULT_SELECTED_CHECK_PARAM_NAME = 'checks'.freeze
6
+ DEFAULT_ERROR_RESPONSE_STATUS = 422
7
+ DEFAULT_SUCCESS_RESPONSE_STATUS = 200
8
+ DEFAULT_SUCCESS_RESPONSE_BODY = "It's alive!".freeze
9
+ DEFAULT_ERRORS_DELIMITER = '; '.freeze
10
+ DEFAULT_SELECTED_CHECK_PARAM_SPLIT_DELIMITER = ','.freeze
11
+
12
+ attr_accessor :healthcheck_path, :full_check_param_name, :selected_check_param_name,
13
+ :error_response_status, :success_response_status, :success_response_body,
14
+ :errors_delimiter, :selected_check_param_split_delimiter, :checkers
15
+
16
+ def initialize
17
+ self.healthcheck_path = DEFAULT_HEALTHCHECK_PATH
18
+ self.full_check_param_name = DEFAULT_FULL_CHECK_PARAM_NAME
19
+ self.selected_check_param_name = DEFAULT_SELECTED_CHECK_PARAM_NAME
20
+ self.error_response_status = DEFAULT_ERROR_RESPONSE_STATUS
21
+ self.success_response_status = DEFAULT_SUCCESS_RESPONSE_STATUS
22
+ self.success_response_body = DEFAULT_SUCCESS_RESPONSE_BODY
23
+ self.errors_delimiter = DEFAULT_ERRORS_DELIMITER
24
+ self.selected_check_param_split_delimiter = DEFAULT_SELECTED_CHECK_PARAM_SPLIT_DELIMITER
25
+ self.checkers = MiddlewareHealthcheck::DefaultCheckers.constants.map do |const|
26
+ klass = MiddlewareHealthcheck::DefaultCheckers.const_get(const)
27
+ klass if klass.is_a? Class
28
+ end.compact
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,8 @@
1
+ if defined? ActiveRecord::Railtie
2
+ require "middleware_healthcheck/default_checkers/active_record_checker"
3
+ end
4
+
5
+ module MiddlewareHealthcheck
6
+ module DefaultCheckers
7
+ end
8
+ end
@@ -0,0 +1,31 @@
1
+ module MiddlewareHealthcheck
2
+ module DefaultCheckers
3
+ class ActiveRecordChecker
4
+ NOT_CONNECTED_ERROR = "Can't connect to database.".freeze
5
+ EXCEPTION_REGEXP = /^ActiveRecord::/.freeze
6
+
7
+ attr_accessor :error
8
+
9
+ def initialize(_app, _env)
10
+ end
11
+
12
+ def healthy?
13
+ ActiveRecord::Base.establish_connection
14
+ ActiveRecord::Base.connection
15
+ if ActiveRecord::Base.connected?
16
+ true
17
+ else
18
+ self.error = NOT_CONNECTED_ERROR
19
+ false
20
+ end
21
+ rescue => e
22
+ if e.class.to_s.match EXCEPTION_REGEXP
23
+ self.error = e.message
24
+ false
25
+ else
26
+ raise e
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,103 @@
1
+ module MiddlewareHealthcheck
2
+ class MainChecker
3
+ QUERY_STRING_KEY = "QUERY_STRING".freeze
4
+ UNDEFINED_CHECKER_ERROR = "Can't find checker: ".freeze
5
+
6
+ attr_accessor :app, :env
7
+
8
+ def initialize(app, env)
9
+ self.app = app
10
+ self.env = env
11
+ end
12
+
13
+ def check_health
14
+ if full_check?
15
+ run_all_checkers
16
+ elsif selected_check?
17
+ run_selected_checkers
18
+ end
19
+
20
+ build_response
21
+ end
22
+
23
+ def build_response
24
+ if errors.present?
25
+ build_error_response
26
+ else
27
+ build_success_response
28
+ end
29
+ end
30
+
31
+ def build_success_response
32
+ build_text_response(
33
+ configuration.success_response_status,
34
+ configuration.success_response_body
35
+ )
36
+ end
37
+
38
+ def build_error_response
39
+ build_text_response(
40
+ configuration.error_response_status,
41
+ errors.join(configuration.errors_delimiter)
42
+ )
43
+ end
44
+
45
+ def build_text_response(status, body)
46
+ [ status, { "Content-Type" => "text/plain" }, [body] ]
47
+ end
48
+
49
+ def run_all_checkers
50
+ run_checkers(configuration.checkers)
51
+ end
52
+
53
+ def run_selected_checkers
54
+ run_checkers(selected_checkers)
55
+ end
56
+
57
+
58
+ def run_checkers(checkers)
59
+ checkers.each do |checker|
60
+ checker_instance = checker.new(@app, @env)
61
+ errors.push(checker_instance.error) unless checker_instance.healthy?
62
+ end
63
+ end
64
+
65
+ def selected_checkers
66
+ selected_checkers_names.map do |checker_name|
67
+ find_checker_by_name(checker_name)
68
+ end.compact
69
+ end
70
+
71
+ def find_checker_by_name(name)
72
+ configuration.checkers.each do |checker|
73
+ return checker if checker.to_s.demodulize.underscore.gsub(/_checker$/, '') == name
74
+ end
75
+ errors.push(UNDEFINED_CHECKER_ERROR + name.camelize)
76
+ nil
77
+ end
78
+
79
+ def selected_checkers_names
80
+ @selected_check_param_names ||= params[configuration.selected_check_param_name]
81
+ .split(configuration.selected_check_param_split_delimiter)
82
+ end
83
+
84
+ def params
85
+ @params ||= Rack::Utils.parse_nested_query(@env[QUERY_STRING_KEY])
86
+ end
87
+
88
+ def errors
89
+ @errors ||= []
90
+ end
91
+
92
+ def full_check?
93
+ params[configuration.full_check_param_name].present?
94
+ end
95
+ def selected_check?
96
+ params[configuration.selected_check_param_name].present?
97
+ end
98
+
99
+ def configuration
100
+ @configuration ||= MiddlewareHealthcheck.configuration
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,17 @@
1
+ module MiddlewareHealthcheck
2
+ class Middleware
3
+ PATH_INFO_KEY = "PATH_INFO".freeze
4
+
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ if env[PATH_INFO_KEY] == MiddlewareHealthcheck.configuration.healthcheck_path
11
+ MainChecker.new(@app, env).check_health
12
+ else
13
+ @app.call(env)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module MiddlewareHealthcheck
2
+ class Railtie < Rails::Railtie
3
+ initializer "middleware_healthcheck.configure_rails_initialization" do
4
+ app.middleware.insert_after Rails::Rack::Logger, MiddlewareHealthcheck::Middleware
5
+ end
6
+
7
+ def app
8
+ Rails.application
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module MiddlewareHealthcheck
2
+ VERSION = '0.2.1'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :middleware_healthcheck do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: middleware_healthcheck
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Adam Wieczorkowski
8
+ - Claudio Perez Gamayo
9
+ - Jan Wieczorkowski
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2019-03-21 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: '4.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '4.0'
29
+ - !ruby/object:Gem::Dependency
30
+ name: sqlite3
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ type: :development
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ - !ruby/object:Gem::Dependency
44
+ name: rspec-rails
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ - !ruby/object:Gem::Dependency
58
+ name: pry-byebug
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ description: Rack middleware to provide a healthcheck endpoint, useful for load balancers
72
+ health checks.
73
+ email:
74
+ - adam.wieczorkowski@naturaily.com
75
+ - claudio@firefield.com
76
+ - jan.wieczorkowski@naturaily.com
77
+ executables: []
78
+ extensions: []
79
+ extra_rdoc_files: []
80
+ files:
81
+ - MIT-LICENSE
82
+ - README.md
83
+ - Rakefile
84
+ - lib/middleware_healthcheck.rb
85
+ - lib/middleware_healthcheck/configuration.rb
86
+ - lib/middleware_healthcheck/default_checkers.rb
87
+ - lib/middleware_healthcheck/default_checkers/active_record_checker.rb
88
+ - lib/middleware_healthcheck/main_checker.rb
89
+ - lib/middleware_healthcheck/middleware.rb
90
+ - lib/middleware_healthcheck/rails.rb
91
+ - lib/middleware_healthcheck/version.rb
92
+ - lib/tasks/middleware_healthcheck_tasks.rake
93
+ homepage: ''
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubygems_version: 3.0.1
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: Rack middleware to provide a healthcheck endpoint.
116
+ test_files: []