Skip to content

Commit

Permalink
Add Sidekiq middleware to clear the ActiveRecord connection pool (issue
Browse files Browse the repository at this point in the history
#16).
  • Loading branch information
postmodern committed May 2, 2024
1 parent 850eb24 commit 6143bb8
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
6 changes: 6 additions & 0 deletions config/sidekiq.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
require 'sidekiq'
require 'redis/namespace'

require_relative '../lib/middleware/sidekiq/active_record_connection_pool'

redis_config = {
url: "redis://#{ENV['REDIS_HOST']}:#{ENV['REDIS_PORT']}"
}

Sidekiq.configure_server do |config|
config.redis = redis_config

config.server_middleware do |chain|
chain.add Middleware::Sidekiq::ActiveRecordConnectionPool
end
end

Sidekiq.configure_client do |config|
Expand Down
47 changes: 47 additions & 0 deletions lib/middleware/sidekiq/active_record_connection_pool.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true
#
# ronin-app - a local web app for Ronin.
#
# Copyright (C) 2023 Hal Brodigan (postmodern.mod3@gmail.com)
#
# ronin-app is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ronin-app is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with ronin-app. If not, see <http://www.gnu.org/licenses/>.
#

require 'active_record'

module Middleware
module Sidekiq
#
# Sidekiq middleware to clear the ActiveRecord connection pool after each
# job.
#
class ActiveRecordConnectionPool

#
# Allows the job to be processed, then clears the ActiveRecord connection
# pool.
#
def call(*)
yield
ensure
begin
ActiveRecord::Base.connection_handler.clear_active_connections!
rescue => error
warn error.message
end
end

end
end
end
46 changes: 46 additions & 0 deletions spec/middleware/sidekiq/active_record_connection_pool_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
require 'spec_helper'
require 'middleware/sidekiq/active_record_connection_pool'

describe Middleware::Sidekiq::ActiveRecordConnectionPool do
describe "#call" do
let(:worker) { double('Worker') }
let(:job) { double('job') }
let(:queue) { double('queue') }

it "must yield then call ActiveRecord::Base.connection_handler.clear_active_connections!" do
expect(ActiveRecord::Base.connection_handler).to receive(:clear_active_connections!)

expect { |b|
subject.call(worker,job,queue,&b)
}.to yield_control
end

context "when the block raises an exception" do
let(:message) { "error!" }
let(:exception) { RuntimeError.new(message) }

it "must still call ActiveRecord::Base.connection_handler.clear_active_connections!" do
expect(ActiveRecord::Base.connection_handler).to receive(:clear_active_connections!)

expect {
subject.call(worker,job,queue) do
raise(exception)
end
}.to raise_error(exception)
end
end

context "when ActiveRecord::Base.connection_handler.clear_active_connections! raises an exception" do
let(:message) { "ActiveRecord error!" }
let(:exception) { RuntimeError.new(message) }

it "must print the error message to stderr" do
expect(ActiveRecord::Base.connection_handler).to receive(:clear_active_connections!).and_raise(exception)

expect { |b|
subject.call(worker,job,queue,&b)
}.to yield_control.and(output("#{message}#{$/}").to_stderr)
end
end
end
end

0 comments on commit 6143bb8

Please sign in to comment.