From 0163e27631fb993bd3541c09a95f0ef5e2026455 Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer <contact@jacobvosmaer.nl>
Date: Wed, 16 Mar 2016 18:10:03 +0100
Subject: [PATCH] Add Gitlab::Redis connection pool

---
 config/application.rb                    |  4 ++--
 config/initializers/session_store.rb     |  2 +-
 config/initializers/sidekiq.rb           |  4 ++--
 config/mail_room.yml                     |  4 ++--
 lib/gitlab/exclusive_lease.rb            |  4 +++-
 lib/gitlab/{redis_config.rb => redis.rb} | 11 ++++++++---
 lib/tasks/cache.rake                     | 25 ++++++++++++------------
 7 files changed, 31 insertions(+), 23 deletions(-)
 rename lib/gitlab/{redis_config.rb => redis.rb} (72%)

diff --git a/config/application.rb b/config/application.rb
index 5a0ac70aa2aab..9633084d6039a 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -4,7 +4,7 @@
 require 'devise'
 I18n.config.enforce_available_locales = false
 Bundler.require(:default, Rails.env)
-require_relative '../lib/gitlab/redis_config'
+require_relative '../lib/gitlab/redis'
 
 module Gitlab
   REDIS_CACHE_NAMESPACE = 'cache:gitlab'
@@ -69,7 +69,7 @@ class Application < Rails::Application
       end
     end
 
-    redis_config_hash = Gitlab::RedisConfig.redis_store_options
+    redis_config_hash = Gitlab::Redis.redis_store_options
     redis_config_hash[:namespace] = REDIS_CACHE_NAMESPACE
     redis_config_hash[:expires_in] = 2.weeks # Cache should not grow forever
     config.cache_store = :redis_store, redis_config_hash
diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb
index 3da5d46be92a4..70285255877b6 100644
--- a/config/initializers/session_store.rb
+++ b/config/initializers/session_store.rb
@@ -13,7 +13,7 @@
 if Rails.env.test?
   Gitlab::Application.config.session_store :cookie_store, key: "_gitlab_session"
 else
-  redis_config = Gitlab::RedisConfig.redis_store_options
+  redis_config = Gitlab::Redis.redis_store_options
   redis_config[:namespace] = 'session:gitlab'
   
   Gitlab::Application.config.session_store(
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index cc83137745ad2..9182d9298097d 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -2,7 +2,7 @@
 
 Sidekiq.configure_server do |config|
   config.redis = {
-    url: Gitlab::RedisConfig.url,
+    url: Gitlab::Redis.url,
     namespace: SIDEKIQ_REDIS_NAMESPACE
   }
 
@@ -29,7 +29,7 @@
 
 Sidekiq.configure_client do |config|
   config.redis = {
-    url: Gitlab::RedisConfig.url,
+    url: Gitlab::Redis.url,
     namespace: SIDEKIQ_REDIS_NAMESPACE
   }
 end
diff --git a/config/mail_room.yml b/config/mail_room.yml
index 60257329f3ebf..761a32adb9ee4 100644
--- a/config/mail_room.yml
+++ b/config/mail_room.yml
@@ -2,7 +2,7 @@
 <%
 require "yaml"
 require "json"
-require_relative "lib/gitlab/redis_config"
+require_relative "lib/gitlab/redis"
 
 rails_env = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
 
@@ -18,7 +18,7 @@ if File.exists?(config_file)
   config['mailbox']    = "inbox"  if config['mailbox'].nil?
 
   if config['enabled'] && config['address']
-    redis_url = Gitlab::RedisConfig.new(rails_env).url
+    redis_url = Gitlab::Redis.new(rails_env).url
     %>
     -
       :host: <%= config['host'].to_json %>
diff --git a/lib/gitlab/exclusive_lease.rb b/lib/gitlab/exclusive_lease.rb
index c73eca832d75c..c2260a5f7acc8 100644
--- a/lib/gitlab/exclusive_lease.rb
+++ b/lib/gitlab/exclusive_lease.rb
@@ -43,7 +43,9 @@ def initialize(key, timeout:)
     # false if the lease is already taken.
     def try_obtain
       # Performing a single SET is atomic
-      !!redis.set(redis_key, '1', nx: true, ex: @timeout)
+      Gitlab::Redis.with do |redis|
+        !!redis.set(redis_key, '1', nx: true, ex: @timeout)
+      end
     end
 
     # No #cancel method. See comments above!
diff --git a/lib/gitlab/redis_config.rb b/lib/gitlab/redis.rb
similarity index 72%
rename from lib/gitlab/redis_config.rb
rename to lib/gitlab/redis.rb
index 4949c6db5392b..d03e6e4cd92c1 100644
--- a/lib/gitlab/redis_config.rb
+++ b/lib/gitlab/redis.rb
@@ -1,14 +1,19 @@
 module Gitlab
-  class RedisConfig
+  class Redis
     attr_reader :url
 
     def self.url
-      new.url
+      @url ||= new.url
+    end
+
+    def self.with
+      @pool ||= ConnectionPool.new { ::Redis.new(url: url) }
+      @pool.with { |redis| yield redis }
     end
     
     def self.redis_store_options
       url = new.url
-      redis_config_hash = Redis::Store::Factory.extract_host_options_from_uri(url)
+      redis_config_hash = ::Redis::Store::Factory.extract_host_options_from_uri(url)
       # Redis::Store does not handle Unix sockets well, so let's do it for them
       redis_uri = URI.parse(url)
       if redis_uri.scheme == 'unix'
diff --git a/lib/tasks/cache.rake b/lib/tasks/cache.rake
index 51e746ef92363..6c2e2e914946c 100644
--- a/lib/tasks/cache.rake
+++ b/lib/tasks/cache.rake
@@ -4,18 +4,19 @@ namespace :cache do
 
   desc "GitLab | Clear redis cache"
   task :clear => :environment do
-    redis = Redis.new(url: Gitlab::RedisConfig.url)
-    cursor = REDIS_SCAN_START_STOP
-    loop do
-      cursor, keys = redis.scan(
-        cursor,
-        match: "#{Gitlab::REDIS_CACHE_NAMESPACE}*", 
-        count: CLEAR_BATCH_SIZE
-      )
-
-      redis.del(*keys) if keys.any?
-
-      break if cursor == REDIS_SCAN_START_STOP
+    Gitlab::Redis.with do |redis|
+      cursor = REDIS_SCAN_START_STOP
+      loop do
+        cursor, keys = redis.scan(
+          cursor,
+          match: "#{Gitlab::REDIS_CACHE_NAMESPACE}*", 
+          count: CLEAR_BATCH_SIZE
+        )
+  
+        redis.del(*keys) if keys.any?
+  
+        break if cursor == REDIS_SCAN_START_STOP
+      end
     end
   end
 end
-- 
GitLab