From 5700f05361082e03c53a652d8c3d0016c7cf343b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Drga?= Date: Fri, 12 Jan 2024 13:01:09 +0100 Subject: [PATCH 1/3] Improved healtcheck, which checks if the app is running and also if the connections to databases are established --- app/controllers/health_controller.rb | 41 +++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb index abfeb52d..9b5831f6 100644 --- a/app/controllers/health_controller.rb +++ b/app/controllers/health_controller.rb @@ -1,5 +1,44 @@ class HealthController < ApplicationController + def index - head :ok + database_check_results = check_db_connections + if all_database_healthy?(database_check_results) + render json: {status: "ok", databases: database_check_results}, status: :ok + else + render json: {status: "error", databases: database_check_results}, status: :internal_server_error + end + end + + private + def all_database_healthy?(database_check_results) + database_check_results.values.all? { |status| status[:status] == "ok" } + end + + def check_db_connections + db_status = {} + databases.each do |role, connection| + db_status[role] = perform_health_check(connection) + ensure + ActiveRecord::Base.clear_active_connections! + end + db_status + end + + def databases + { + primary: ActiveRecord::Base.connected_to(role: :writing) { ApplicationRecord.connection }, + datahub: ActiveRecord::Base.connected_to(role: :reading) { DatahubRecord.connection } + } + end + + def perform_health_check(connection) + if connection + connection.execute('SELECT 1') + {status: 'ok'} + else + {status: 'error', message: 'Connection not established'} + end + rescue => e + {status: 'error', message: e.message} end end From 3f59237a8b5336b4f7964212383d5a885a8eb331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Drga?= Date: Wed, 17 Jan 2024 11:23:16 +0100 Subject: [PATCH 2/3] Modified healthcheck test to include databases checks --- spec/features/health_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/features/health_spec.rb b/spec/features/health_spec.rb index eca08d9c..8266633b 100644 --- a/spec/features/health_spec.rb +++ b/spec/features/health_spec.rb @@ -5,5 +5,11 @@ visit health_path expect(page.status_code).to be(200) + + returned_data = JSON.parse(page.body) + + expect(returned_data["status"]).to eq("ok") + expect(returned_data["databases"]["primary"]).to include("status" => "ok") + expect(returned_data["databases"]["datahub"]).to include("status" => "ok") end end From 9a6dce887c4a296762a7fdb78ef95b500517f7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Drga?= Date: Tue, 23 Jan 2024 20:26:15 +0100 Subject: [PATCH 3/3] health_spec test includes coverage for negative scenarios, modified the index of health_controller --- app/controllers/health_controller.rb | 10 +++--- spec/features/health_spec.rb | 49 ++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb index 9b5831f6..76c84e0e 100644 --- a/app/controllers/health_controller.rb +++ b/app/controllers/health_controller.rb @@ -3,10 +3,12 @@ class HealthController < ApplicationController def index database_check_results = check_db_connections if all_database_healthy?(database_check_results) - render json: {status: "ok", databases: database_check_results}, status: :ok + render json: {status: "ok"}, status: :ok else - render json: {status: "error", databases: database_check_results}, status: :internal_server_error + render json: {status: "fail"}, status: :internal_server_error end + rescue StandardError + render json: {status: "fail"}, status: :internal_server_error end private @@ -36,9 +38,7 @@ def perform_health_check(connection) connection.execute('SELECT 1') {status: 'ok'} else - {status: 'error', message: 'Connection not established'} + {status: 'fail'} end - rescue => e - {status: 'error', message: e.message} end end diff --git a/spec/features/health_spec.rb b/spec/features/health_spec.rb index 8266633b..f3852c3e 100644 --- a/spec/features/health_spec.rb +++ b/spec/features/health_spec.rb @@ -1,15 +1,50 @@ require 'rails_helper' RSpec.feature "Healthcheck", type: :feature do - scenario 'As a healthcheck bot I want to check if everything is ok' do - visit health_path + context 'when healthcheck passes' do + scenario 'With healthcheck I want to check if everything is ok' do + visit health_path - expect(page.status_code).to be(200) + expect(page.status_code).to be(200) - returned_data = JSON.parse(page.body) + returned_data = JSON.parse(page.body) - expect(returned_data["status"]).to eq("ok") - expect(returned_data["databases"]["primary"]).to include("status" => "ok") - expect(returned_data["databases"]["datahub"]).to include("status" => "ok") + expect(returned_data["status"]).to eq("ok") + end + end + + context 'when healthcheck fails' do + scenario 'unexpected error in health check' do + allow_any_instance_of(HealthController).to receive(:all_database_healthy?).and_raise(StandardError, 'Unexpected error') + + visit health_path + + expect(page.status_code).to be(500) + returned_data = JSON.parse(page.body) + + expect(returned_data["status"]).to eq("fail") + end + + scenario 'primary database fails' do + allow(ApplicationRecord.connection).to receive(:execute).and_raise(StandardError, 'Something went wrong in primary db') + + visit health_path + + expect(page.status_code).to be(500) + returned_data = JSON.parse(page.body) + + expect(returned_data["status"]).to eq("fail") + end + + scenario 'datahub database fails' do + allow(DatahubRecord.connection).to receive(:execute).and_raise(StandardError, 'Something went wrong in datahub db') + + visit health_path + + expect(page.status_code).to be(500) + returned_data = JSON.parse(page.body) + + expect(returned_data["status"]).to eq("fail") + end end end