hey_doctor 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +97 -0
  4. data/Rakefile +10 -0
  5. data/app/services/hey_doctor/check_application_health_service.rb +29 -0
  6. data/app/services/hey_doctor/check_database_health_service.rb +43 -0
  7. data/app/services/hey_doctor/check_redis_health_service.rb +31 -0
  8. data/lib/hey_doctor.rb +22 -0
  9. data/lib/hey_doctor/engine.rb +10 -0
  10. data/lib/hey_doctor/version.rb +5 -0
  11. data/lib/tasks/hey_doctor_tasks.rake +5 -0
  12. data/spec/dummy/Rakefile +6 -0
  13. data/spec/dummy/app/assets/config/manifest.js +1 -0
  14. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  15. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  16. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  17. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  18. data/spec/dummy/app/controllers/home_controller.rb +5 -0
  19. data/spec/dummy/app/javascript/packs/application.js +15 -0
  20. data/spec/dummy/app/jobs/application_job.rb +7 -0
  21. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  22. data/spec/dummy/app/models/application_record.rb +3 -0
  23. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  24. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  25. data/spec/dummy/bin/rails +4 -0
  26. data/spec/dummy/bin/rake +4 -0
  27. data/spec/dummy/bin/setup +33 -0
  28. data/spec/dummy/config.ru +11 -0
  29. data/spec/dummy/config/application.rb +42 -0
  30. data/spec/dummy/config/boot.rb +5 -0
  31. data/spec/dummy/config/cable.yml +10 -0
  32. data/spec/dummy/config/database.yml +21 -0
  33. data/spec/dummy/config/environment.rb +5 -0
  34. data/spec/dummy/config/environments/development.rb +66 -0
  35. data/spec/dummy/config/environments/production.rb +113 -0
  36. data/spec/dummy/config/environments/test.rb +59 -0
  37. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  38. data/spec/dummy/config/initializers/backtrace_silencers.rb +8 -0
  39. data/spec/dummy/config/initializers/cors.rb +16 -0
  40. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  41. data/spec/dummy/config/initializers/inflections.rb +16 -0
  42. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  43. data/spec/dummy/config/initializers/redis.rb +1 -0
  44. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  45. data/spec/dummy/config/locales/en.yml +33 -0
  46. data/spec/dummy/config/puma.rb +43 -0
  47. data/spec/dummy/config/routes.rb +3 -0
  48. data/spec/dummy/config/storage.yml +34 -0
  49. data/spec/dummy/db/schema.rb +18 -0
  50. data/spec/dummy/log/development.log +1693 -0
  51. data/spec/dummy/log/test.log +1258 -0
  52. data/spec/dummy/tmp/development_secret.txt +1 -0
  53. data/spec/dummy/tmp/pids/server.pid +1 -0
  54. data/spec/lib/hey_doctor/hey_doctor_spec.rb +42 -0
  55. data/spec/rails_helper.rb +27 -0
  56. data/spec/requests/health_check_spec.rb +28 -0
  57. data/spec/services/hey_doctor/check_application_health_service_spec.rb +46 -0
  58. data/spec/services/hey_doctor/check_database_health_service_spec.rb +91 -0
  59. data/spec/services/hey_doctor/check_redis_health_service_spec.rb +56 -0
  60. data/spec/spec_helper.rb +25 -0
  61. metadata +240 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '0824d2e802a96ba8586c63f1ee7a193ca8675ce69b35d73f0dcdaeebf7c5e082'
4
+ data.tar.gz: 567451703ce9ead34d72691ba51071e8c11e39c9086d5cf9cec63b5e04feca38
5
+ SHA512:
6
+ metadata.gz: f5add1a4598b39cc55c0f5b50855e1089caf5e3f5728a08988a75e98b0e4cf1fa1a98a4eeb43e286cf1234cd818ea33f0e91c8e6aed596d6cbf52dd84a4b91c9
7
+ data.tar.gz: f022c57f63cfa656aea89af82e0d85d8c57349634c73fd45a9f4c109a520774159d1f92b0d26c39ac24e414a9aeb2c990bddd317d313685457c08257691069b2
@@ -0,0 +1,20 @@
1
+ Copyright 2021 Matheus A Martins
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.
@@ -0,0 +1,97 @@
1
+ # HeyDoctor - doc c'mon man!
2
+
3
+ ![banner](banner.png)
4
+
5
+ This is a simple stack health check for rails based applications, it mounts a endpoint with the current status of database, application and redis.
6
+
7
+ ## Usage
8
+
9
+ After installing this gem it will mount a endpoint in `/_ah/health`, this will bring a response like this:
10
+
11
+ `curl localhost:8000/_ah/health`
12
+
13
+ ```json
14
+ {
15
+ "app":{
16
+ "message":"Application is running",
17
+ "success":true
18
+ },
19
+ "database":{
20
+ "message":"Database is connected",
21
+ "success":true
22
+ },
23
+ "redis":{
24
+ "message":"Redis is connected",
25
+ "success":true
26
+ }
27
+ }
28
+ ```
29
+
30
+ ## Installation
31
+
32
+ If you have a redis instance in you application add the following initializer to create a `Redis.current`, so it don't need to use global vars, or create a new connection each request:
33
+
34
+ ```ruby
35
+ # config/initializers/redis.rb
36
+
37
+ Redis.current ||= Redis.new(url: ENV['REDIS_URL'])
38
+ ```
39
+
40
+ Add this line to your application's Gemfile:
41
+
42
+ ```ruby
43
+ gem 'hey_doctor'
44
+ ```
45
+
46
+ And then execute:
47
+ ```bash
48
+ bundle install
49
+ ```
50
+
51
+ After installing the gem just mount the HealthCheck endpoint inside config.ru:
52
+
53
+ ```ruby
54
+ # config.ru
55
+
56
+ # bunch of requires here
57
+ require "hey_doctor"
58
+
59
+ map '/_ah/health' do
60
+ run HeyDoctor::Rack::HealthCheck.new
61
+ end
62
+
63
+ ...
64
+ ```
65
+
66
+ ## Developing
67
+
68
+ ```bash
69
+ docker-compose build && docker-compose up
70
+
71
+ docker-compose exec web bash
72
+
73
+ rails db:setup
74
+
75
+ rubocop -A && rspec
76
+ ```
77
+
78
+ Minimum coverage is set to 95%.
79
+
80
+ ## Releasing
81
+
82
+ Change the tag in `lib/hey_doctor/version.rb` each release using [SEMVER](https://semver.org/lang/pt-BR/).
83
+
84
+ ```bash
85
+ bundle exec rake build
86
+ # build gem in pkg/hey_doctor-TAG.gem
87
+
88
+ bundle exec rake release
89
+ # Ask for rubygems credentials and makes the release
90
+ ```
91
+ ## Contributing
92
+
93
+ Fell free to send a PR.
94
+
95
+ ## License
96
+
97
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+
5
+ APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
6
+ load 'rails/tasks/engine.rake'
7
+
8
+ load 'rails/tasks/statistics.rake'
9
+
10
+ require 'bundler/gem_tasks'
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HeyDoctor::CheckApplicationHealthService
4
+ class << self
5
+ SUCCESS = {
6
+ message: 'Application is running',
7
+ success: true
8
+ }.freeze
9
+
10
+ ERROR = {
11
+ message: 'Application down, call the firefighters',
12
+ success: false
13
+ }.freeze
14
+
15
+ def call
16
+ return SUCCESS if responding?
17
+
18
+ ERROR
19
+ end
20
+
21
+ private
22
+
23
+ def responding?
24
+ Net::HTTP.start('localhost', 8000) { |http| http.head('/') }.code == '200'
25
+ rescue StandardError
26
+ false
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HeyDoctor::CheckDatabaseHealthService
4
+ class << self
5
+ SUCCESS = {
6
+ message: 'Database is connected',
7
+ success: true
8
+ }.freeze
9
+
10
+ MIGRATION_PENDING = {
11
+ message: 'Pending migrations detected',
12
+ success: true
13
+ }.freeze
14
+
15
+ ERROR = {
16
+ message: 'Error connecting to database',
17
+ success: false
18
+ }.freeze
19
+
20
+ def call
21
+ return ERROR unless connected?
22
+ return MIGRATION_PENDING if needs_migration?
23
+
24
+ SUCCESS
25
+ end
26
+
27
+ private
28
+
29
+ def connected?
30
+ ActiveRecord::Base.connection.execute('select 1')
31
+
32
+ true
33
+ rescue ActiveRecord::StatementInvalid, ActiveRecord::NoDatabaseError
34
+ false
35
+ end
36
+
37
+ def needs_migration?
38
+ return false unless connected?
39
+
40
+ ActiveRecord::Base.connection.migration_context.needs_migration?
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HeyDoctor::CheckRedisHealthService
4
+ class << self
5
+ SUCCESS = {
6
+ message: 'Redis is connected',
7
+ success: true
8
+ }.freeze
9
+
10
+ ERROR = {
11
+ message: 'Error connecting to redis',
12
+ success: false
13
+ }.freeze
14
+
15
+ def call
16
+ return SUCCESS if connected?
17
+
18
+ ERROR
19
+ end
20
+
21
+ private
22
+
23
+ def connected?
24
+ Redis.current.get('viva_a_sociedade_alternativa')
25
+
26
+ true
27
+ rescue Redis::CannotConnectError, NameError
28
+ false
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'hey_doctor/version'
4
+ require 'hey_doctor/engine'
5
+
6
+ module HeyDoctor::Rack
7
+ class HealthCheck
8
+ def call(_env)
9
+ [200, {}, [status]]
10
+ end
11
+
12
+ private
13
+
14
+ def status
15
+ {
16
+ app: ::HeyDoctor::CheckApplicationHealthService.call,
17
+ database: ::HeyDoctor::CheckDatabaseHealthService.call,
18
+ redis: ::HeyDoctor::CheckRedisHealthService.call
19
+ }.to_json
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class HeyDoctor::Engine < ::Rails::Engine
4
+ isolate_namespace HeyDoctor
5
+ config.generators.api_only = true
6
+
7
+ config.generators do |generators|
8
+ generators.test_framework :rspec
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HeyDoctor
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ # desc "Explaining what the task does"
3
+ # task :hey_doctor do
4
+ # # Task goes here
5
+ # end
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative "config/application"
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Channel < ActionCable::Channel::Base
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module ApplicationCable
2
+ class Connection < ActionCable::Connection::Base
3
+ end
4
+ end
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::API
2
+ end
@@ -0,0 +1,5 @@
1
+ class HomeController < ApplicationController
2
+ def index
3
+ render :ok, json: { funfa: 'sim' }
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require rails-ujs
14
+ //= require activestorage
15
+ //= require_tree .
@@ -0,0 +1,7 @@
1
+ class ApplicationJob < ActiveJob::Base
2
+ # Automatically retry jobs that encountered a deadlock
3
+ # retry_on ActiveRecord::Deadlocked
4
+
5
+ # Most jobs are safe to ignore if the underlying records are no longer available
6
+ # discard_on ActiveJob::DeserializationError
7
+ end
@@ -0,0 +1,4 @@
1
+ class ApplicationMailer < ActionMailer::Base
2
+ default from: 'from@example.com'
3
+ layout 'mailer'
4
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationRecord < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ end
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
+ <style>
6
+ /* Email styles need to be inline */
7
+ </style>
8
+ </head>
9
+
10
+ <body>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
@@ -0,0 +1 @@
1
+ <%= yield %>
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../config/application', __dir__)
3
+ require_relative "../config/boot"
4
+ require "rails/commands"
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative "../config/boot"
3
+ require "rake"
4
+ Rake.application.run
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ require "fileutils"
3
+
4
+ # path to your application root.
5
+ APP_ROOT = File.expand_path('..', __dir__)
6
+
7
+ def system!(*args)
8
+ system(*args) || abort("\n== Command #{args} failed ==")
9
+ end
10
+
11
+ FileUtils.chdir APP_ROOT do
12
+ # This script is a way to set up or update your development environment automatically.
13
+ # This script is idempotent, so that you can run it at any time and get an expectable outcome.
14
+ # Add necessary setup steps to this file.
15
+
16
+ puts '== Installing dependencies =='
17
+ system! 'gem install bundler --conservative'
18
+ system('bundle check') || system!('bundle install')
19
+
20
+ # puts "\n== Copying sample files =="
21
+ # unless File.exist?('config/database.yml')
22
+ # FileUtils.cp 'config/database.yml.sample', 'config/database.yml'
23
+ # end
24
+
25
+ puts "\n== Preparing database =="
26
+ system! 'bin/rails db:prepare'
27
+
28
+ puts "\n== Removing old logs and tempfiles =="
29
+ system! 'bin/rails log:clear tmp:clear'
30
+
31
+ puts "\n== Restarting application server =="
32
+ system! 'bin/rails restart'
33
+ end