Skip to content

Implement connection pooling in Familia::Connection module #14

@delano

Description

@delano

Description

Currently, the Familia::Connection module manages individual Redis connections without pooling. Implementing a connection pool can significantly improve performance and resource management, especially in high-concurrency scenarios. Here's a recommended approach to implement a connection pool within the Familia::Connection module:

Proposed solution

  1. Use a robust connection pooling library:
    Consider using the 'connection_pool' gem, which is widely used and well-maintained.

  2. Modify the Connection module:

    • Add methods for configuring pool size and timeout
    • Implement a connection_pool method to manage pools for different URIs
    • Create a with_redis method for executing blocks with pooled connections
    • Update the existing redis method to use the connection pool
require 'connection_pool'

module Familia
  module Connection
    # ... existing code ...

    # Size of the connection pool
    @pool_size = 5
    # Timeout for checking out a connection from the pool (in seconds)
    @pool_timeout = 5

    # Configure the connection pool
    #
    # @param size [Integer] The number of connections to keep in the pool
    # @param timeout [Integer] The number of seconds to wait for a connection
    def configure_pool(size: 5, timeout: 5)
      @pool_size = size
      @pool_timeout = timeout
    end

    # Get or create a connection pool for a given URI
    #
    # @param uri [String, URI, nil] The URI of the Redis server
    # @return [ConnectionPool] The connection pool for the specified URI
    def connection_pool(uri = nil)
      uri = URI.parse(uri) if uri.is_a?(String)
      uri ||= Familia.uri

      @redis_pools ||= {}
      @redis_pools[uri.serverid] ||= ConnectionPool.new(size: @pool_size, timeout: @pool_timeout) do
        connect(uri)
      end
    end

    # Execute a block of code with a Redis connection from the pool
    #
    # @param uri [String, URI, nil] The URI of the Redis server
    # @yield [Redis] The Redis connection
    # @return [Object] The result of the block
    def with_redis(uri = nil)
      connection_pool(uri).with do |redis|
        yield redis
      end
    end

    # Override the existing redis method to use the connection pool
    def redis(uri = nil)
      warn "DEPRECATION WARNING: Direct access to redis is deprecated. Use 'with_redis' instead."
      connection_pool(uri).with { |r| r }
    end
  end
end
  1. Update usage in your application:

Instead of directly calling Familia.redis.get(key), you would now use:

Familia.with_redis do |redis|
  redis.get(key)
end

Expected behavior

After implementing connection pooling:

  1. The module will efficiently manage a fixed number of Redis connections.
  2. Multiple threads will be able to use different connections simultaneously.
  3. The pool will automatically handle connection recovery if connections are lost.
  4. Users will be able to configure pool sizes and timeouts to suit their needs.
  5. Usage pattern will change from direct Redis access to using a block-based approach with with_redis.

Additional notes

  • Update documentation to reflect these changes and guide users on proper usage of pooled connections.
  • Consider adding configuration options for users to set pool sizes and timeouts based on their specific requirements.
  • Implement a deprecation warning for direct redis method access to encourage migration to the new with_redis pattern.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions