Module: Familia::Connection
- Includes:
- Middleware, Operations
- Included in:
- Familia
- Defined in:
- lib/familia/connection.rb,
lib/familia/connection/behavior.rb,
lib/familia/connection/handlers.rb,
lib/familia/connection/middleware.rb,
lib/familia/connection/operations.rb,
lib/familia/connection/operation_core.rb,
lib/familia/connection/pipelined_core.rb,
lib/familia/connection/transaction_core.rb,
lib/familia/connection/individual_command_proxy.rb
Overview
The Connection module provides Database connection management for Familia. It allows easy setup and access to Database clients across different URIs with robust connection pooling for thread safety.
Defined Under Namespace
Modules: Behavior, Handler, Middleware, OperationCore, Operations, PipelineCore, TransactionCore Classes: CachedConnectionHandler, CreateConnectionHandler, FiberConnectionHandler, FiberPipelineHandler, FiberTransactionHandler, IndividualCommandProxy, ParentDelegationHandler, ProviderConnectionHandler, ResponsibilityChain, StandaloneConnectionHandler
Constant Summary collapse
- DefaultConnectionHandler =
CreateConnectionHandler
Instance Attribute Summary collapse
-
#connection_provider ⇒ Proc
The provider should accept a URI string and return a Redis connection already connected to the correct database specified in the URI.
-
#uri ⇒ URI
(also: #url)
The default URI for Database connections.
Attributes included from Middleware
#enable_database_counter, #enable_database_logging
Instance Method Summary collapse
-
#build_connection_chain ⇒ Object
Builds the connection chain with handlers in priority order.
-
#create_dbclient(uri = nil) ⇒ Redis
(also: #connect, #isolated_dbclient)
Creates a new Database connection instance.
-
#dbclient(uri = nil) ⇒ Redis
Retrieves a Database connection using the Chain of Responsibility pattern.
-
#normalize_uri(uri) ⇒ Object
Normalizes various URI formats to a consistent URI object Made public so handlers can use it.
Methods included from Operations
#atomic_write, #pipelined, #transaction, #with_dbclient, #with_isolated_dbclient
Methods included from Middleware
#clear_fiber_connection!, #fiber_connection=, #increment_middleware_version!, #middleware_version, #reconnect!
Instance Attribute Details
#connection_provider ⇒ Proc
The provider should accept a URI string and return a Redis connection already connected to the correct database specified in the URI.
Contract
Familia calls the provider every time it needs a client and never hands the connection back -- there is no check-in hook. The provider must therefore return a client that remains exclusively usable by the caller without a matching check-in.
pool.with { |conn| conn } does NOT satisfy that contract: with checks
the connection back in the moment its block returns, so the client handed
to Familia is simultaneously available to every other checkout. Under
concurrency two threads end up issuing commands on one connection, and
per-connection state (MULTI, WATCH, SELECT, SUBSCRIBE) crosses callers.
ConnectionPool::Wrapper (alias ConnectionPool.wrap) does satisfy it:
it proxies each command through pool.with, so a connection is checked
out for exactly the duration of that command and checked back in
afterwards. ConnectionPool's checkout is reentrant per fiber, so a
MULTI/EXEC, a pipeline, or a WATCH-guarded transaction still runs
entirely on one connection.
Build the pool once, outside the lambda. A ConnectionPool.new inside
the provider mints a fresh pool -- and eventually a fresh connection --
on every call.
88 89 90 |
# File 'lib/familia/connection.rb', line 88 def connection_provider @connection_provider end |
#uri ⇒ URI Also known as: url
Returns The default URI for Database connections.
31 32 33 |
# File 'lib/familia/connection.rb', line 31 def uri @uri end |
Instance Method Details
#build_connection_chain ⇒ Object
Builds the connection chain with handlers in priority order
159 160 161 162 163 164 165 166 |
# File 'lib/familia/connection.rb', line 159 def build_connection_chain ResponsibilityChain.new .add_handler(Familia::Connection::FiberPipelineHandler.instance) .add_handler(Familia::Connection::FiberTransactionHandler.instance) .add_handler(FiberConnectionHandler.new) .add_handler(ProviderConnectionHandler.new) .add_handler(CreateConnectionHandler.new) end |
#create_dbclient(uri = nil) ⇒ Redis Also known as: connect, isolated_dbclient
Creates a new Database connection instance.
This method always creates a fresh connection and does not use caching. Each call returns a new Redis client instance that you are responsible for managing and closing when done.
126 127 128 129 130 131 132 133 |
# File 'lib/familia/connection.rb', line 126 def create_dbclient(uri = nil) parsed_uri = normalize_uri(uri) # Register middleware only once, globally register_middleware_once Redis.new(parsed_uri.conf.merge(timeout: 5)) end |
#dbclient(uri = nil) ⇒ Redis
Retrieves a Database connection using the Chain of Responsibility pattern. Handles DB selection automatically based on the URI.
Thread-safe: Uses double-checked locking pattern to avoid mutex overhead on the hot path. Only acquires mutex during initial lazy initialization. MRI's GIL provides implicit memory barriers making this pattern safe.
147 148 149 150 151 152 153 154 155 156 |
# File 'lib/familia/connection.rb', line 147 def dbclient(uri = nil) # Fast path - read with local variable to ensure single read chain = @connection_chain return chain.handle(uri) if chain # Slow path - initialization only @connection_chain_mutex.synchronize do @connection_chain ||= build_connection_chain end.handle(uri) end |
#normalize_uri(uri) ⇒ Object
Normalizes various URI formats to a consistent URI object Made public so handlers can use it
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/familia/connection.rb', line 170 def normalize_uri(uri) case uri when Integer new_uri = Familia.uri.dup new_uri.db = uri new_uri when ->(obj) { obj.is_a?(String) || obj.instance_of?(::String) } URI.parse(uri) when URI uri when nil Familia.uri else raise ArgumentError, "Invalid URI type: #{uri.class.name}" end end |