diff --git a/.release-version b/.release-version index ec6d649b..815d5ca0 100644 --- a/.release-version +++ b/.release-version @@ -1 +1 @@ -1.18.1 +1.19.0 diff --git a/Gemfile b/Gemfile index c4661e77..61666267 100644 --- a/Gemfile +++ b/Gemfile @@ -10,6 +10,7 @@ gem 'concurrent-ruby', '<= 1.3.4' # see https://github.com/rails/rails/issues/54 gem 'csv' gem 'drb' gem 'exception_notification' +gem 'faraday' # used for Sequencescape health check gem 'hashie' gem 'jquery-rails' gem 'json_api_client' diff --git a/Gemfile.lock b/Gemfile.lock index c0811f51..ff2d8288 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -96,7 +96,7 @@ GEM base64 (0.3.0) benchmark (0.5.0) bigdecimal (4.0.1) - bootsnap (1.21.1) + bootsnap (1.23.0) msgpack (~> 1.2) bootstrap-datepicker-rails (1.10.0.1) railties (>= 3.0) @@ -130,31 +130,15 @@ GEM actionmailer (>= 5.2, < 9) activesupport (>= 5.2, < 9) execjs (2.10.0) - faraday (1.10.3) - faraday-em_http (~> 1.0) - faraday-em_synchrony (~> 1.0) - faraday-excon (~> 1.1) - faraday-httpclient (~> 1.0) - faraday-multipart (~> 1.0) - faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.0) - faraday-patron (~> 1.0) - faraday-rack (~> 1.0) - faraday-retry (~> 1.0) - ruby2_keywords (>= 0.0.4) - faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) - faraday-excon (1.1.0) - faraday-httpclient (1.0.1) - faraday-multipart (1.0.4) - multipart-post (~> 2) - faraday-net_http (1.0.1) - faraday-net_http_persistent (1.2.0) - faraday-patron (1.0.0) - faraday-rack (1.0.0) - faraday-retry (1.0.3) - faraday_middleware (1.2.0) - faraday (~> 1.0) + faraday (2.14.1) + faraday-net_http (>= 2.0, < 3.5) + json + logger + faraday-gzip (2.0.1) + faraday (>= 1.0) + zlib (~> 3.0) + faraday-net_http (3.4.2) + net-http (~> 0.5) ffi (1.17.3-arm64-darwin) ffi (1.17.3-x86_64-darwin) ffi (1.17.3-x86_64-linux-gnu) @@ -169,12 +153,12 @@ GEM railties (>= 4.2.0) thor (>= 0.14, < 2.0) json (2.18.1) - json_api_client (1.21.0) - activemodel (>= 3.2.0) - activesupport (>= 3.2.0) + json_api_client (1.23.0) + activemodel (>= 6.0.0) + activesupport (>= 6.0.0) addressable (~> 2.2) - faraday (>= 0.15.2, < 2.0) - faraday_middleware (>= 0.9.0, < 2.0) + faraday (>= 1.10, < 3.0) + faraday-gzip (>= 1.0, < 3.0) rack (>= 0.2) language_server-protocol (3.17.0.5) launchy (3.1.1) @@ -207,12 +191,13 @@ GEM minitest-rails-capybara (0.0.2) capybara minitest-rails - mocha (3.0.1) + mocha (3.0.2) ruby2_keywords (>= 0.0.5) msgpack (1.8.0) multi_json (1.15.0) - multipart-post (2.3.0) mutex_m (0.3.0) + net-http (0.9.1) + uri (>= 0.11.1) net-imap (0.5.12) date net-protocol @@ -223,13 +208,13 @@ GEM net-smtp (0.5.1) net-protocol nio4r (2.7.5) - nokogiri (1.18.10-arm64-darwin) + nokogiri (1.19.1-arm64-darwin) racc (~> 1.4) - nokogiri (1.18.10-x86_64-darwin) + nokogiri (1.19.1-x86_64-darwin) racc (~> 1.4) - nokogiri (1.18.10-x86_64-linux-gnu) + nokogiri (1.19.1-x86_64-linux-gnu) racc (~> 1.4) - oj (3.16.13) + oj (3.16.15) bigdecimal (>= 3.0) ostruct (>= 0.2) ostruct (0.6.3) @@ -247,7 +232,7 @@ GEM puma (7.2.0) nio4r (~> 2.0) racc (1.8.1) - rack (2.2.21) + rack (2.2.22) rack-test (2.2.0) rack (>= 1.3) rails (7.0.10) @@ -324,7 +309,7 @@ GEM sprockets-rails tilt securerandom (0.4.1) - selenium-webdriver (4.40.0) + selenium-webdriver (4.41.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) @@ -363,6 +348,7 @@ GEM unicode-display_width (3.2.0) unicode-emoji (~> 4.1) unicode-emoji (4.2.0) + uri (1.1.1) websocket (1.2.11) websocket-driver (0.8.0) base64 @@ -372,6 +358,7 @@ GEM nokogiri (~> 1.8) yard (0.9.38) zeitwerk (2.7.3) + zlib (3.2.2) PLATFORMS arm64-darwin-22 @@ -391,6 +378,7 @@ DEPENDENCIES csv drb exception_notification + faraday hashie jquery-rails json_api_client diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb new file mode 100644 index 00000000..77a2f556 --- /dev/null +++ b/app/controllers/health_controller.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class HealthController < ActionController::Base # rubocop:disable Rails/ApplicationController + # Inherits from ActionController::Base to avoid implied dependencies on Sequencescape + + # Health endpoint + # + # Check connection to Sequencescape by making a health request, returns 200 if successful, or 502/504 if not. + def show + sequencescape_conn.get('/health') + render plain: 'OK', status: :ok + rescue Faraday::TimeoutError + render plain: 'Connection to Sequencescape timed out', status: :gateway_timeout + rescue Faraday::Error + render plain: 'Sequencescape is unavailable', status: :bad_gateway + end + + def sequencescape_conn + @sequencescape_conn ||= Faraday.new(url: sequencescape_url) do |faraday| + faraday.response :raise_error # raise Faraday::Error on status code 4xx or 5xx + end + end + + private + + def sequencescape_url + Gatekeeper::Application.config.api_connection_options[:url] + end +end diff --git a/config/routes.rb b/config/routes.rb index 8d11834b..da9c87a8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -7,6 +7,8 @@ # You can have the root of your site routed with "root" root 'pages#index' + get 'health' => 'health#show', as: :health + resources :lots, only: %i[create show new], constraints: { id: /[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/ } do collection do get :search diff --git a/test/controllers/health_controller_test.rb b/test/controllers/health_controller_test.rb new file mode 100644 index 00000000..a669f85c --- /dev/null +++ b/test/controllers/health_controller_test.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +require 'test_helper' + +class HealthControllerTest < ActionController::TestCase + test 'returns OK when Sequencescape is available' do + test_conn = Faraday.new do |builder| + builder.adapter :test, Faraday::Adapter::Test::Stubs.new do |stub| + stub.get('/health') { |_env| [200, {}, 'OK'] } + end + end + @controller.stubs(:sequencescape_conn).returns(test_conn) + + get :show + assert_response :success + assert_equal 'OK', @response.body + end + + test 'returns Gateway Timeout when Sequencescape connection times out' do + test_conn = Faraday.new do |builder| + builder.adapter :test, Faraday::Adapter::Test::Stubs.new do |stub| + stub.get('/health') { |_env| raise Faraday::TimeoutError } + end + end + @controller.stubs(:sequencescape_conn).returns(test_conn) + + get :show + assert_response :gateway_timeout + assert_equal 'Connection to Sequencescape timed out', @response.body + end + + test 'returns Bad Gateway when Sequencescape is unavailable' do + test_conn = Faraday.new do |builder| + builder.adapter :test, Faraday::Adapter::Test::Stubs.new do |stub| + stub.get('/health') { |_env| raise Faraday::ServerError, 'Internal server error' } + end + end + @controller.stubs(:sequencescape_conn).returns(test_conn) + + get :show + assert_response :bad_gateway + assert_equal 'Sequencescape is unavailable', @response.body + end +end