Skip to content

Commit

Permalink
Merge pull request #121 from pulibrary/add_solr_monitor
Browse files Browse the repository at this point in the history
Add solr monitor
  • Loading branch information
lbeder authored Jul 26, 2024
2 parents 48bc16c + 20ee526 commit 7678b86
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 1 deletion.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ gem 'sidekiq', '>= 3.0'
gem 'spork'
gem 'sqlite3', '~> 1.3'
gem 'timecop'
gem 'webmock'

gemspec
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ The following services are currently supported:
* Sidekiq
* Resque
* Delayed Job
* Solr

## Configuration

Expand Down Expand Up @@ -312,6 +313,10 @@ Please note that `url` or `connection` can't be used at the same time.

* `queue_size`: the size (maximum) of a queue which is considered unhealthy (the default is 100).

### Solr

* `url`: the URL used to connect to your Solr instance - must be a string. You can also use `url` to explicitly configure authentication (e.g., `'https://user:[email protected]:8983/'`)

### Adding a Custom Provider

It's also possible to add custom health check providers suited for your needs (of course, it's highly appreciated and encouraged if you'd contribute useful providers to the project).
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails_6.1.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ gem 'sidekiq', '>= 3.0'
gem 'spork'
gem 'sqlite3', '~> 1.3'
gem 'timecop'
gem 'webmock'

gemspec path: '../'
1 change: 1 addition & 0 deletions gemfiles/rails_7.1_.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ gem 'sidekiq', '>= 3.0'
gem 'spork'
gem 'sqlite3', '~> 1.3'
gem 'timecop'
gem 'webmock'

gemspec path: '../'
2 changes: 1 addition & 1 deletion lib/health_monitor/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module HealthMonitor
class Configuration
PROVIDERS = %i[cache database delayed_job redis resque sidekiq].freeze
PROVIDERS = %i[cache database delayed_job redis resque sidekiq solr].freeze

attr_accessor :basic_auth_credentials,
:environment_variables,
Expand Down
60 changes: 60 additions & 0 deletions lib/health_monitor/providers/solr.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# frozen_string_literal: true

require 'health_monitor/providers/base'

module HealthMonitor
module Providers
class SolrException < StandardError; end

class Solr < Base
class Configuration < Base::Configuration
DEFAULT_URL = nil
attr_accessor :url

def initialize(provider)
super(provider)

@url = DEFAULT_URL
end
end

def check!
check_solr_connection!
rescue Exception => e
raise SolrException.new(e.message)
end

private

def configuration_class
::HealthMonitor::Providers::Solr::Configuration
end

def check_solr_connection!
json = JSON.parse(solr_response.body)
raise "The solr has an invalid status #{status_uri}" if json['responseHeader']['status'] != 0
end

def status_uri
@status_uri ||= begin
uri = URI(configuration.url)
uri.path = '/solr/admin/cores'
uri.query = 'action=STATUS'
uri
end
end

def solr_request
@solr_request ||= begin
req = Net::HTTP::Get.new(status_uri)
req.basic_auth(status_uri.user, status_uri.password) if status_uri.user && status_uri.password
req
end
end

def solr_response
Net::HTTP.start(status_uri.hostname, status_uri.port) { |http| http.request(solr_request) }
end
end
end
end
121 changes: 121 additions & 0 deletions spec/lib/health_monitor/providers/solr_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# frozen_string_literal: true

require 'spec_helper'

describe HealthMonitor::Providers::Solr do
subject { described_class.new }

context 'with defaults' do
it { expect(subject.configuration.name).to eq('Solr') }
it { expect(subject.configuration.url).to eq(HealthMonitor::Providers::Solr::Configuration::DEFAULT_URL) }
end

describe '#name' do
it { expect(subject.name).to eq('Solr') }
end

describe '#check!' do
let(:solr_url_config) { 'http://www.example-solr.com:8983' }

before do
subject.request = test_request
subject.configure do |config|
config.url = solr_url_config
end
Providers.stub_solr
end

context 'with a standard connection' do
it 'checks against the configured solr url' do
subject.check!
expect(Providers.stub_solr).to have_been_requested
end

it 'succesfully checks' do
expect {
subject.check!
}.not_to raise_error
end

context 'when failing' do
before do
Providers.stub_solr_failure
end

it 'fails check!' do
expect {
subject.check!
}.to raise_error(HealthMonitor::Providers::SolrException)
end

it 'checks against the configured solr url' do
expect {
subject.check!
}.to raise_error(HealthMonitor::Providers::SolrException)
expect(Providers.stub_solr_failure).to have_been_requested
end
end
end

context 'with a configured url that includes a path' do
let(:solr_url_config) { 'http://www.example-solr.com:8983/solr/blacklight-core-development' }

it 'checks against the configured solr url' do
subject.check!
expect(Providers.stub_solr).to have_been_requested
end
end

context 'with a connection with authentication' do
let(:solr_url_config) { 'http://solr:SolrRocks@localhost:8888' }

before { Providers.stub_solr_with_auth }

it 'checks against the configured solr url' do
subject.check!
expect(Providers.stub_solr_with_auth).to have_been_requested
end

it 'succesfully checks' do
expect {
subject.check!
}.not_to raise_error
end

context 'when failing' do
before do
Providers.stub_solr_failure_with_auth
end

it 'fails check!' do
expect {
subject.check!
}.to raise_error(HealthMonitor::Providers::SolrException)
end

it 'checks against the configured solr url' do
expect {
subject.check!
}.to raise_error(HealthMonitor::Providers::SolrException)
expect(Providers.stub_solr_failure_with_auth).to have_been_requested
end
end
end
end

describe '#configure' do
before do
subject.configure
end

let(:url) { 'solr://user:[email protected]:8983/' }

it 'url can be configured' do
expect {
subject.configure do |config|
config.url = url
end
}.to change { subject.configuration.url }.to(url)
end
end
end
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
require 'timecop'
require 'mock_redis'
require 'sidekiq/testing'
require 'webmock/rspec'

Dir[File.expand_path('../lib/**/*.rb', __dir__)].sort.each { |f| require f }
Dir[File.expand_path('support/**/*.rb', __dir__)].sort.each { |f| require f }
Expand Down
24 changes: 24 additions & 0 deletions spec/support/providers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,28 @@ def stub_sidekiq_over_retry_limit_failure
allow(retry_set).to receive(:select).and_return([item: { retry_count: retry_count }])
allow(Sidekiq::RetrySet).to receive(:new).and_return(retry_set)
end

def stub_solr
WebMock.stub_request(:get, 'http://www.example-solr.com:8983/solr/admin/cores?action=STATUS').to_return(
body: { responseHeader: { status: 0 } }.to_json, headers: { 'Content-Type' => 'text/json' }
)
end

def stub_solr_failure
WebMock.stub_request(:get, 'http://www.example-solr.com:8983/solr/admin/cores?action=STATUS').to_return(
body: { responseHeader: { status: 500 } }.to_json, headers: { 'Content-Type' => 'text/json' }
)
end

def stub_solr_with_auth
WebMock.stub_request(:get, 'http://localhost:8888/solr/admin/cores?action=STATUS')
.with(headers: { 'Authorization' => 'Basic c29scjpTb2xyUm9ja3M=', 'Host' => 'localhost:8888' })
.to_return(body: { responseHeader: { status: 0 } }.to_json, headers: { 'Content-Type' => 'text/json' })
end

def stub_solr_failure_with_auth
WebMock.stub_request(:get, 'http://localhost:8888/solr/admin/cores?action=STATUS')
.with(headers: { 'Authorization' => 'Basic c29scjpTb2xyUm9ja3M=', 'Host' => 'localhost:8888' })
.to_return(body: { responseHeader: { status: 500 } }.to_json, headers: { 'Content-Type' => 'text/json' })
end
end

0 comments on commit 7678b86

Please sign in to comment.