From 9caef1c49bb21cfd689f3eb6358ea7e78cd77b3a Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Tue, 13 Oct 2020 10:57:45 +0100 Subject: [PATCH 1/6] Add healthcheck for Mongoid This is used in place of ActiveRecord quite a few of our apps [1]. Note that the check is pinched from the Internet [2]. [1]: https://github.com/alphagov/travel-advice-publisher/pull/973 [2]: https://stackoverflow.com/questions/28446274/how-can-i-check-the-connection-of-mongoid --- lib/govuk_app_config/govuk_healthcheck.rb | 1 + .../govuk_healthcheck/mongoid.rb | 14 +++++++++ spec/lib/govuk_healthcheck/mongoid_spec.rb | 31 +++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 lib/govuk_app_config/govuk_healthcheck/mongoid.rb create mode 100644 spec/lib/govuk_healthcheck/mongoid_spec.rb diff --git a/lib/govuk_app_config/govuk_healthcheck.rb b/lib/govuk_app_config/govuk_healthcheck.rb index 5733dd1f..1cbba207 100644 --- a/lib/govuk_app_config/govuk_healthcheck.rb +++ b/lib/govuk_app_config/govuk_healthcheck.rb @@ -1,5 +1,6 @@ require "govuk_app_config/govuk_healthcheck/checkup" require "govuk_app_config/govuk_healthcheck/active_record" +require "govuk_app_config/govuk_healthcheck/mongoid" require "govuk_app_config/govuk_healthcheck/sidekiq_redis" require "govuk_app_config/govuk_healthcheck/threshold_check" require "govuk_app_config/govuk_healthcheck/sidekiq_queue_check" diff --git a/lib/govuk_app_config/govuk_healthcheck/mongoid.rb b/lib/govuk_app_config/govuk_healthcheck/mongoid.rb new file mode 100644 index 00000000..64de50a3 --- /dev/null +++ b/lib/govuk_app_config/govuk_healthcheck/mongoid.rb @@ -0,0 +1,14 @@ +module GovukHealthcheck + class Mongoid + def name + :database_connectivity + end + + def status + ::Mongoid.default_client.database_names.any? + GovukHealthcheck::OK + rescue StandardError + GovukHealthcheck::CRITICAL + end + end +end diff --git a/spec/lib/govuk_healthcheck/mongoid_spec.rb b/spec/lib/govuk_healthcheck/mongoid_spec.rb new file mode 100644 index 00000000..15443325 --- /dev/null +++ b/spec/lib/govuk_healthcheck/mongoid_spec.rb @@ -0,0 +1,31 @@ +require "spec_helper" +require "govuk_app_config/govuk_healthcheck" +require_relative "shared_interface" + +RSpec.describe GovukHealthcheck::Mongoid do + let(:client) { double(:client, database_names: %w[db]) } + let(:mongoid) { double(:mongoid, default_client: client) } + before { stub_const("Mongoid", mongoid) } + + describe ".status" do + context "when the database is connected" do + it_behaves_like "a healthcheck" + + it "returns OK" do + expect(subject.status).to eq(GovukHealthcheck::OK) + end + end + + context "when the database is not connected" do + before do + allow(client).to receive(:database_names) { raise } + end + + it_behaves_like "a healthcheck" + + it "returns CRITICAL" do + expect(subject.status).to eq(GovukHealthcheck::CRITICAL) + end + end + end +end From 7afd17dbb9fcf47bea045c6372df36367b5dc304 Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Tue, 13 Oct 2020 11:14:07 +0100 Subject: [PATCH 2/6] Add healthcheck for remote Rails cache We use a local Memcached instance for the cache store in several of our apps [1] [2]. If the cache is unavailable, it will print error logs but an exception won't be thrown. While the behaviour is graceful, it's still a problem that the caching we rely on is not working as expected, so we should surface this in healthchecks. [1]: https://github.com/alphagov/collections/blob/a08857d95771e813338fbbe8542a8f5b536ea6d4/config/environments/production.rb#L58 [2]: https://github.com/alphagov/whitehall/blob/774eb78cd4c75622e786bdb18762850cd0b91840/config/environments/production.rb#L61 --- lib/govuk_app_config/govuk_healthcheck.rb | 1 + .../govuk_healthcheck/rails_cache.rb | 16 +++++++ .../lib/govuk_healthcheck/rails_cache_spec.rb | 43 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 lib/govuk_app_config/govuk_healthcheck/rails_cache.rb create mode 100644 spec/lib/govuk_healthcheck/rails_cache_spec.rb diff --git a/lib/govuk_app_config/govuk_healthcheck.rb b/lib/govuk_app_config/govuk_healthcheck.rb index 1cbba207..0244e6be 100644 --- a/lib/govuk_app_config/govuk_healthcheck.rb +++ b/lib/govuk_app_config/govuk_healthcheck.rb @@ -1,6 +1,7 @@ require "govuk_app_config/govuk_healthcheck/checkup" require "govuk_app_config/govuk_healthcheck/active_record" require "govuk_app_config/govuk_healthcheck/mongoid" +require "govuk_app_config/govuk_healthcheck/rails_cache" require "govuk_app_config/govuk_healthcheck/sidekiq_redis" require "govuk_app_config/govuk_healthcheck/threshold_check" require "govuk_app_config/govuk_healthcheck/sidekiq_queue_check" diff --git a/lib/govuk_app_config/govuk_healthcheck/rails_cache.rb b/lib/govuk_app_config/govuk_healthcheck/rails_cache.rb new file mode 100644 index 00000000..fbf951b9 --- /dev/null +++ b/lib/govuk_app_config/govuk_healthcheck/rails_cache.rb @@ -0,0 +1,16 @@ +module GovukHealthcheck + class RailsCache + def name + :rails_cache + end + + def status + ::Rails.cache.write("healthcheck-cache", true) + raise unless ::Rails.cache.read("healthcheck-cache") + + GovukHealthcheck::OK + rescue StandardError + GovukHealthcheck::CRITICAL + end + end +end diff --git a/spec/lib/govuk_healthcheck/rails_cache_spec.rb b/spec/lib/govuk_healthcheck/rails_cache_spec.rb new file mode 100644 index 00000000..23d7be74 --- /dev/null +++ b/spec/lib/govuk_healthcheck/rails_cache_spec.rb @@ -0,0 +1,43 @@ +require "spec_helper" +require "govuk_app_config/govuk_healthcheck" +require_relative "shared_interface" + +RSpec.describe GovukHealthcheck::RailsCache do + let(:cache) { double(:cache, write: true, read: true) } + let(:rails) { double(:mongoid, cache: cache) } + before { stub_const("Rails", rails) } + + describe ".status" do + context "when the cache is available" do + it_behaves_like "a healthcheck" + + it "returns OK" do + expect(subject.status).to eq(GovukHealthcheck::OK) + end + end + + context "when the cache is silently unavailable" do + before do + allow(cache).to receive(:read) { false } + end + + it_behaves_like "a healthcheck" + + it "returns CRITICAL" do + expect(subject.status).to eq(GovukHealthcheck::CRITICAL) + end + end + + context "when the cache is loudly unavailable" do + before do + allow(cache).to receive(:read) { raise } + end + + it_behaves_like "a healthcheck" + + it "returns CRITICAL" do + expect(subject.status).to eq(GovukHealthcheck::CRITICAL) + end + end + end +end From 160afeaa8db8cbfe61ff084079f3f0c0871a2c1d Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Tue, 13 Oct 2020 11:24:45 +0100 Subject: [PATCH 3/6] Update healthchecks.md doc with new checks --- docs/healthchecks.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/healthchecks.md b/docs/healthchecks.md index f481d081..68dc8eca 100644 --- a/docs/healthchecks.md +++ b/docs/healthchecks.md @@ -73,6 +73,15 @@ if it must be subclassed to work, but a concrete class which works on its own doesn't need that suffix. You should aim to follow this convention in your own apps, ideally putting custom health checks into a `Healthcheck` module. +### `RailsCache` + +This checks that the Rails cache store, such as Memcached, is acessible by +writing and reading back a cache entry called "healthcheck-cache". + +### `Mongoid` + +This checks that the app has a connection to its Mongo database via Mongoid. + ### `SidekiqRedis` This checks that the app has a connection to Redis via Sidekiq. From 972066d2b3ae40f235fbc8048632989dbb667c23 Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Tue, 13 Oct 2020 11:25:28 +0100 Subject: [PATCH 4/6] Bump version to 2.4.0 --- CHANGELOG.md | 5 +++++ lib/govuk_app_config/version.rb | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20144951..8c9de382 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 2.4.0 + +* Add new GovukHealthcheck::Mongoid check +* Add new GovukHealthcheck::RailsCache check + # 2.3.0 * Remove unused SidekiqQueueSizeCheck healthcheck base class diff --git a/lib/govuk_app_config/version.rb b/lib/govuk_app_config/version.rb index a25cc16f..e871b138 100644 --- a/lib/govuk_app_config/version.rb +++ b/lib/govuk_app_config/version.rb @@ -1,3 +1,3 @@ module GovukAppConfig - VERSION = "2.3.0".freeze + VERSION = "2.4.0".freeze end From 985cfdb78eeda13054793e4802a13f6781c4731a Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Tue, 13 Oct 2020 11:48:41 +0100 Subject: [PATCH 5/6] Fix surprise linting error This has arisen due to a mismatch in the version of rubocop-ast. --- .../rails_ext/action_dispatch/debug_exceptions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/govuk_app_config/rails_ext/action_dispatch/debug_exceptions.rb b/lib/govuk_app_config/rails_ext/action_dispatch/debug_exceptions.rb index ed40aacf..76b6e733 100644 --- a/lib/govuk_app_config/rails_ext/action_dispatch/debug_exceptions.rb +++ b/lib/govuk_app_config/rails_ext/action_dispatch/debug_exceptions.rb @@ -27,7 +27,7 @@ def self.should_monkey_patch_log_error?(clazz = ::ActionDispatch::DebugException def self.monkey_patch_log_error(clazz = ::ActionDispatch::DebugExceptions) clazz.class_eval do - private + private def log_error(request, wrapper) logger = logger(request) From 1b2e76a86caae9a17b5a2bf0d74eabc96ce790f1 Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Tue, 13 Oct 2020 11:57:21 +0100 Subject: [PATCH 6/6] Remove unnecessary version lock on bundler gem This is causing the build to break when testing against Ruby 2.7, and isn't something we have in our other gems. --- govuk_app_config.gemspec | 1 - 1 file changed, 1 deletion(-) diff --git a/govuk_app_config.gemspec b/govuk_app_config.gemspec index 24c86c90..cf2fd5e1 100644 --- a/govuk_app_config.gemspec +++ b/govuk_app_config.gemspec @@ -25,7 +25,6 @@ Gem::Specification.new do |spec| spec.add_dependency "statsd-ruby", "~> 1.4.0" spec.add_dependency "unicorn", ">= 5.4", "< 5.8" - spec.add_development_dependency "bundler", "~> 1.15" spec.add_development_dependency "climate_control" spec.add_development_dependency "rack-test", "~> 1.1.0" spec.add_development_dependency "rails", "~> 6"