Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added support for redis connection pools #839

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
3 changes: 3 additions & 0 deletions lib/flipper/adapter.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
require 'flipper/adapters/poolable'

module Flipper
# Adding a module include so we have some hooks for stuff down the road
module Adapter
def self.included(base)
base.extend(ClassMethods)
base.include(::Flipper::Adapters::Poolable)
end

module ClassMethods
Expand Down
31 changes: 31 additions & 0 deletions lib/flipper/adapters/poolable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module Flipper
module Adapters
module Poolable
def initialize(client_or_pool = nil, key_prefix: nil)
@pool = nil
@client = nil
if client_or_pool.respond_to?(:with)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe is_a?(ConnectionPool) might be better

@pool = client_or_pool
else
@client = client_or_pool
end
@key_prefix = key_prefix
end

def self.included(klass)
klass.superclass.instance_methods(false).each do |method|
klass.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
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.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