Skip to content

Commit

Permalink
added support for redis connection pools
Browse files Browse the repository at this point in the history
  • Loading branch information
j-castellanos committed Feb 12, 2024
1 parent 3c4ec2f commit 3f70f76
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 50 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ gem 'mysql2'
gem 'pg'
gem 'cuprite'
gem 'puma'
gem 'connection_pool'

group(:guard) do
gem 'guard'
Expand Down
32 changes: 32 additions & 0 deletions lib/flipper/adapters/redis_pool.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require 'flipper/adapters/redis'
require 'connection_pool'

module Flipper
module Adapters
class RedisPool < Redis
def initialize(pool, key_prefix: nil)
@pool = pool
@key_prefix = key_prefix
end

superclass.instance_methods(false).each do |method|
define_method method do |*args|
return super(*args) unless @client.nil?

@pool.with do |client|
@client = client
super(*args).tap { @client = nil }
end
end
end
end
end
end


Flipper.configure do |config|
config.adapter do
client = ConnectionPool.new(size: 1) { Redis.new(url: ENV["FLIPPER_REDIS_URL"] || ENV["REDIS_URL"]) }
Flipper::Adapters::RedisPool.new(client)
end
end
10 changes: 10 additions & 0 deletions spec/flipper/adapters/redis_pool_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require 'flipper/adapters/redis_pool'

RSpec.describe Flipper::Adapters::RedisPool do
subject do
pool = ConnectionPool.new(size: 1, &create_client)
described_class.new(pool, key_prefix: key_prefix)
end

it_behaves_like "a redis adapter"
end
52 changes: 2 additions & 50 deletions spec/flipper/adapters/redis_spec.rb
Original file line number Diff line number Diff line change
@@ -1,55 +1,7 @@
require 'flipper/adapters/redis'

RSpec.describe Flipper::Adapters::Redis do
let(:client) do
options = {}
subject { described_class.new(client, key_prefix: key_prefix) }

options[:url] = ENV['REDIS_URL'] if ENV['REDIS_URL']

Redis.raise_deprecations = true
Redis.new(options)
end

subject { described_class.new(client) }

before do
skip_on_error(Redis::CannotConnectError, 'Redis not available') do
client.flushdb
end
end

it_should_behave_like 'a flipper adapter'

it 'configures itself on load' do
Flipper.configuration = nil
Flipper.instance = nil

silence { load 'flipper/adapters/redis.rb' }

expect(Flipper.adapter.adapter).to be_a(Flipper::Adapters::Redis)
end

describe 'with a key_prefix' do
let(:subject) { described_class.new(client, key_prefix: "lockbox:") }
let(:feature) { Flipper::Feature.new(:search, subject) }

it_should_behave_like 'a flipper adapter'

it 'namespaces feature-keys' do
subject.add(feature)

expect(client.smembers("flipper_features")).to eq([])
expect(client.exists?("search")).to eq(false)
expect(client.smembers("lockbox:flipper_features")).to eq(["search"])
expect(client.hgetall("lockbox:search")).not_to eq(nil)
end

it "can remove namespaced keys" do
subject.add(feature)
expect(client.smembers("lockbox:flipper_features")).to eq(["search"])

subject.remove(feature)
expect(client.smembers("lockbox:flipper_features")).to be_empty
end
end
it_behaves_like "a redis adapter"
end
55 changes: 55 additions & 0 deletions spec/support/examples/redis_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
RSpec.shared_examples "a redis adapter" do
let(:create_client) do
Proc.new do
options = {}

options[:url] = ENV['REDIS_URL'] if ENV['REDIS_URL']

Redis.raise_deprecations = true
Redis.new(options)
end
end
let(:client) { create_client.call }
let(:key_prefix) { nil }

before do
skip_on_error(Redis::CannotConnectError, 'Redis not available') do
client.flushdb
end
end

it_should_behave_like 'a flipper adapter'

it 'configures itself on load' do
Flipper.configuration = nil
Flipper.instance = nil

silence { load 'flipper/adapters/redis_pool.rb' }

expect(Flipper.adapter.adapter).to be_a(described_class)
end

describe 'with a key_prefix' do
let(:feature) { Flipper::Feature.new(:search, subject) }
let(:key_prefix) { "lockbox:" }

it_should_behave_like 'a flipper adapter'

it 'namespaces feature-keys' do
subject.add(feature)

expect(client.smembers("flipper_features")).to eq([])
expect(client.exists?("search")).to eq(false)
expect(client.smembers("lockbox:flipper_features")).to eq(["search"])
expect(client.hgetall("lockbox:search")).not_to eq(nil)
end

it "can remove namespaced keys" do
subject.add(feature)
expect(client.smembers("lockbox:flipper_features")).to eq(["search"])

subject.remove(feature)
expect(client.smembers("lockbox:flipper_features")).to be_empty
end
end
end
15 changes: 15 additions & 0 deletions test/adapters/redis_pool_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
require 'test_helper'
require 'flipper/adapters/redis_pool'

class RedisPoolTest < MiniTest::Test
prepend Flipper::Test::SharedAdapterTests

def setup
url = ENV.fetch('REDIS_URL', 'redis://localhost:6379')
pool = ConnectionPool.new(size: 1) { Redis.new(url: url) }
pool.with { |client| client.flushdb }
@adapter = Flipper::Adapters::RedisPool.new(pool)
rescue Redis::CannotConnectError
ENV['CI'] ? raise : skip('Redis not available')
end
end

0 comments on commit 3f70f76

Please sign in to comment.