Skip to content

Commit 77d6f18

Browse files
authored
Connection Pool for Redis (#448)
* Connection Pool for Redis * Removed comments * Using Stealth::RedisSupport instead of $redis * Added bigdecimal for ruby >= 3.4 * Removed pry gems * Removed pry gems * Added bigdecimal * Added mutex_m gem * Updated Gemfile.lock * Updated CI * Removed unnecessary gems * Updated redis gem version * Update CI truffleruby-head to truffleruby
1 parent 10b6f8e commit 77d6f18

12 files changed

Lines changed: 122 additions & 35 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,11 @@ jobs:
1111
strategy:
1212
fail-fast: false
1313
matrix:
14-
os: [ubuntu-20.04, ubuntu-22.04, macos-latest]
15-
ruby: [ 2.7, 3.0, 3.1, 3.2, truffleruby-head ]
14+
os: [ubuntu-22.04, macos-latest]
15+
ruby: [ 3.3, truffleruby ]
1616
exclude:
1717
- os: ubuntu-22.04
18-
ruby: 2.7
19-
- os: ubuntu-22.04
20-
ruby: truffleruby-head
18+
ruby: truffleruby
2119

2220
runs-on: ${{ matrix.os }}
2321

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
.yardoc
1111
doc/
1212
*.gem
13+
/.idea

Gemfile.lock

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
PATH
22
remote: .
33
specs:
4-
stealth (2.0.0.beta7)
4+
stealth (2.1.0)
55
activesupport (~> 7.0)
6+
connection_pool (~> 2.4)
67
multi_json (~> 1.12)
78
puma (~> 6.0)
89
redis (~> 5.0)
@@ -19,11 +20,13 @@ GEM
1920
i18n (>= 1.6, < 2)
2021
minitest (>= 5.1)
2122
tzinfo (~> 2.0)
22-
concurrent-ruby (1.2.2)
23-
connection_pool (2.4.1)
23+
base64 (0.3.0)
24+
concurrent-ruby (1.3.5)
25+
connection_pool (2.5.3)
2426
diff-lcs (1.5.0)
2527
i18n (1.13.0)
2628
concurrent-ruby (~> 1.0)
29+
logger (1.7.0)
2730
minitest (5.18.0)
2831
mock_redis (0.36.0)
2932
ruby2_keywords
@@ -34,14 +37,14 @@ GEM
3437
oj (3.14.3)
3538
puma (6.3.0)
3639
nio4r (~> 2.0)
37-
rack (2.2.7)
40+
rack (2.2.17)
3841
rack-protection (3.0.6)
3942
rack
4043
rack-test (2.1.0)
4144
rack (>= 1.3)
42-
redis (5.0.6)
43-
redis-client (>= 0.9.0)
44-
redis-client (0.14.1)
45+
redis (5.4.1)
46+
redis-client (>= 0.22.0)
47+
redis-client (0.25.1)
4548
connection_pool
4649
rspec (3.12.0)
4750
rspec-core (~> 3.12.0)
@@ -57,11 +60,12 @@ GEM
5760
rspec-support (~> 3.12.0)
5861
rspec-support (3.12.0)
5962
ruby2_keywords (0.0.5)
60-
sidekiq (7.1.2)
61-
concurrent-ruby (< 2)
63+
sidekiq (7.3.9)
64+
base64
6265
connection_pool (>= 2.3.0)
66+
logger
6367
rack (>= 2.2.4)
64-
redis-client (>= 0.14.0)
68+
redis-client (>= 0.22.2)
6569
sinatra (3.0.6)
6670
mustermann (~> 3.0)
6771
rack (~> 2.2, >= 2.2.4)

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.0.0.beta7
1+
2.1.0

lib/stealth/base.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
require 'stealth/logger'
2222
require 'stealth/configuration'
2323
require 'stealth/reloader'
24+
require 'stealth/redis'
2425

2526
# helpers
2627
require 'stealth/helpers/redis'

lib/stealth/controller/catch_all.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def run_catch_all(err:)
5252
private
5353

5454
def fetch_error_level
55-
if fail_attempts = $redis.get(error_slug)
55+
if fail_attempts = Stealth::RedisSupport.with { |r| r.get(error_slug) }
5656
begin
5757
fail_attempts = Integer(fail_attempts)
5858
rescue ArgumentError
@@ -65,7 +65,7 @@ def fetch_error_level
6565
end
6666

6767
# Set the error with an expiration to avoid filling Redis
68-
$redis.setex(error_slug, 15.minutes.to_i, fail_attempts)
68+
Stealth::RedisSupport.with { |r| r.setex(error_slug, 15.minutes.to_i, fail_attempts) }
6969

7070
fail_attempts
7171
end

lib/stealth/helpers/redis.rb

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,28 @@ def get_key(key, expiration: Stealth.config.session_ttl)
1212
if expiration > 0
1313
getex(key, expiration)
1414
else
15-
$redis.get(key)
15+
Stealth::RedisSupport.with { |r| r.get(key) }
1616
end
1717
end
1818

1919
def delete_key(key)
20-
$redis.del(key)
20+
Stealth::RedisSupport.with { |r| r.del(key) }
2121
end
2222

2323
def getex(key, expiration=Stealth.config.session_ttl)
24-
$redis.multi do |pipeline|
25-
pipeline.expire(key, expiration)
26-
pipeline.get(key)
27-
end.last
24+
Stealth::RedisSupport.with do |r|
25+
r.multi do |pipeline|
26+
pipeline.expire(key, expiration)
27+
pipeline.get(key)
28+
end.last
29+
end
2830
end
2931

3032
def persist_key(key:, value:, expiration: Stealth.config.session_ttl)
3133
if expiration > 0
32-
$redis.setex(key, expiration, value)
34+
Stealth::RedisSupport.with { |r| r.setex(key, expiration, value) }
3335
else
34-
$redis.set(key, value)
36+
Stealth::RedisSupport.with { |r| r.set(key, value) }
3537
end
3638
end
3739

lib/stealth/redis.rb

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# frozen_string_literal: true
2+
3+
require "redis"
4+
require "connection_pool"
5+
6+
module Stealth
7+
class RedisConfig
8+
attr_accessor :url, :pool_size, :pool_timeout
9+
10+
def initialize
11+
@url = Stealth.env.development? ? "redis://localhost:6379/0" : ENV["STEALTH_REDIS_URL"] || ENV["REDIS_URL"]
12+
@pool_size = Integer(ENV["STEALTH_REDIS_POOL"] || 5)
13+
@pool_timeout = Integer(ENV["STEALTH_REDIS_TIMEOUT"] || 5)
14+
end
15+
16+
def to_redis_kwargs
17+
{ url: url }
18+
end
19+
end
20+
21+
module RedisSupport
22+
class << self
23+
def config
24+
@config ||= RedisConfig.new
25+
end
26+
27+
def configure
28+
yield(config)
29+
reset_pool!
30+
end
31+
32+
def pool
33+
@pool ||= build_pool
34+
end
35+
36+
def with(&blk)
37+
pool.with(&blk)
38+
end
39+
40+
def connection_pool
41+
pool
42+
end
43+
44+
def reset_pool!
45+
if defined?(@pool) && @pool
46+
@pool.shutdown(&:close) rescue nil
47+
end
48+
@pool = nil
49+
end
50+
51+
private
52+
53+
def build_pool
54+
ConnectionPool.new(size: config.pool_size, timeout: config.pool_timeout) do
55+
::Redis.new(**config.to_redis_kwargs)
56+
end
57+
end
58+
end
59+
end
60+
end
61+

lib/stealth/session.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ def initialize(id: nil, type: :primary)
2020
@type = type
2121

2222
if id.present?
23-
unless defined?($redis) && $redis.present?
23+
unless defined?(Stealth::RedisSupport) && Stealth::RedisSupport.connection_pool.present?
2424
raise(
2525
Stealth::Errors::RedisNotConfigured,
26-
"Please make sure REDIS_URL is configured before using sessions"
26+
"Please make sure STEALTH_REDIS_URL or REDIS_URL is configured before using sessions"
2727
)
2828
end
2929

@@ -91,7 +91,7 @@ def set_session(new_flow:, new_state:)
9191
end
9292

9393
def clear_session
94-
$redis.del(session_key)
94+
Stealth::RedisSupport.with { |r| r.del(session_key) }
9595
end
9696

9797
def present?

spec/session_spec.rb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,12 @@ class FlowMap
2020
describe "Stealth::Session" do
2121
let(:id) { '0xDEADBEEF' }
2222

23-
it "should raise an error if $redis is not set" do
24-
$redis = nil
23+
it "should raise an error if Stealth::RedisSupport connection_pool is not set" do
24+
allow(Stealth::RedisSupport).to receive(:connection_pool).and_return(nil)
2525

2626
expect {
2727
Stealth::Session.new(id: id)
2828
}.to raise_error(Stealth::Errors::RedisNotConfigured)
29-
30-
$redis = MockRedis.new
3129
end
3230

3331
describe "without a session" do

0 commit comments

Comments
 (0)