Module: Familia::Horreum::Connection

Includes:
Connection::Behavior
Defined in:
lib/familia/horreum/connection.rb

Overview

Connection - Mixed instance and class-level methods for Valkey connection management Provides connection handling, transactions, and URI normalization for both class-level operations (e.g., Customer.dbclient) and instance-level operations (e.g., customer.dbclient)

Includes shared connection behavior from Familia::Connection::Behavior, providing:

  • URI normalization (normalize_uri)
  • Connection creation (create_dbclient)
  • Transaction method signatures
  • Pipeline method signatures

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Connection::Behavior

#create_dbclient, #normalize_uri

Instance Attribute Details

#uriObject Also known as: url

Returns the value of attribute uri.



20
21
22
# File 'lib/familia/horreum/connection.rb', line 20

def uri
  @uri
end

Instance Method Details

#connectObject



45
46
47
# File 'lib/familia/horreum/connection.rb', line 45

def connect(*)
  create_dbclient(*)
end

#dbclient(uri = nil) ⇒ Redis

Returns the Database connection for the class using Chain of Responsibility pattern.

This method uses a chain of handlers to resolve connections in priority order:

  1. FiberTransactionHandler - Fiber:familia_transaction
  2. DefaultConnectionHandler - Horreum model class-level @dbclient
  3. GlobalFallbackHandler - Familia.dbclient(uri || logical_database) (global fallback)

Thread-safe lazy initialization using double-checked locking to ensure only a single connection chain is built even under high concurrent load.

Returns:

  • (Redis)

    the Database connection instance.



34
35
36
37
38
39
40
41
42
43
# File 'lib/familia/horreum/connection.rb', line 34

def dbclient(uri = nil)
  # Fast path: return existing chain if already initialized
  return @class_connection_chain.handle(uri) if @class_connection_chain

  # Slow path: thread-safe initialization
  @class_connection_chain_mutex.synchronize do
    @class_connection_chain ||= build_connection_chain
  end
  @class_connection_chain.handle(uri)
end

#pipelined(&block) {|Redis| ... } ⇒ MultiResult Also known as: pipeline

Note:

Connection Inheritance:

  • Uses object's logical_database setting if configured
  • Inherits class-level database settings
  • Falls back to instance-level dbclient if set
  • Uses global connection chain as final fallback
Note:

Pipeline Context:

  • When called outside global pipeline: Creates local MultiResult
  • When called inside global pipeline: Yields to existing pipeline
  • Maintains proper Fiber-local state for nested calls
Note:

Performance Considerations:

  • Best for multiple independent operations on the same object
  • Reduces network latency by batching commands
  • Commands execute independently (some may succeed, others fail)

Executes Redis commands in a pipeline using this object's connection context.

Batches multiple Redis commands together and sends them in a single network round-trip for improved performance. Uses the object's database and connection settings. Returns a MultiResult object for consistency with global methods.

Examples:

Basic instance pipeline

customer = Customer.new(custid: 'cust_123')
result = customer.pipelined do |conn|
  conn.hset(customer.dbkey, 'last_login', Time.now.to_i)
  conn.hincrby(customer.dbkey, 'login_count', 1)
  conn.sadd('recent_logins', customer.identifier)
  conn.hget(customer.dbkey, 'login_count')
end
result.successful?        # => true
result.results           # => ["OK", 15, "OK", "15"]
result.results.last      # => "15" (new login count)

Performance optimization for object operations

user = User.new(userid: 'user_456')

# Instead of multiple round-trips:
# user.save                    # Round-trip 1
# user.tags.add('premium')     # Round-trip 2
# user.sessions.clear          # Round-trip 3

# Use pipeline for single round-trip:
result = user.pipelined do |conn|
  conn.hmset(user.dbkey, user.to_h_for_storage)
  conn.sadd(user.tags.dbkey, 'premium')
  conn.del(user.sessions.dbkey)
end
# All operations completed in one network round-trip

Using with object's database context

class Session < Familia::Horreum
  logical_database 3  # Use database 3
  field :user_id
  field :expires_at
end

session = Session.new(session_id: 'sess_789')
result = session.pipelined do |conn|
  # Commands automatically execute in database 3
  conn.hset(session.dbkey, 'user_id', 'user_123')
  conn.hset(session.dbkey, 'expires_at', 1.hour.from_now.to_i)
  conn.expire(session.dbkey, 3600)
end

Reentrant behavior with global pipelines

customer = Customer.new(custid: 'cust_abc')

# When called within a global pipeline, reuses the pipeline connection
result = Familia.pipelined do |global_conn|
  global_conn.set('global_counter', 0)

  # This reuses the same pipeline connection
  customer.pipelined do |local_conn|
    local_conn.hset(customer.dbkey, 'updated', Time.now.to_i)
    Redis::Future.new  # Returns Redis::Future in nested context
  end
end

Parameters:

  • block (Proc)

    The block containing Redis commands to execute in pipeline

Yields:

  • (Redis)

    conn The Redis connection configured for pipelined mode

Returns:

  • (MultiResult)

    Result object with success status and command results

Raises:

  • (Familia::OperationModeError)

    When called with incompatible connection handlers (e.g., FiberConnectionHandler or CachedConnectionHandler that don't support pipelines)

See Also:



233
234
235
236
# File 'lib/familia/horreum/connection.rb', line 233

def pipelined(&block)
  ensure_relatives_initialized!
  Familia::Connection::PipelineCore.execute_pipeline(-> { dbclient }, &block)
end

#transaction {|conn| ... } ⇒ MultiResult Also known as: multi

Note:

This method works with the global Familia.transaction context when available

Note:

Connection Inheritance:

  • Uses object's logical_database setting if configured
  • Inherits class-level database settings
  • Falls back to instance-level dbclient if set
  • Uses global connection chain as final fallback
Note:

Transaction Context:

  • When called outside global transaction: Creates local MultiResult
  • When called inside global transaction: Yields to existing transaction
  • Maintains proper Fiber-local state for nested calls

Perform a sacred Database transaction ritual.

This method creates a protective circle around your Database operations, ensuring they all succeed or fail together. It's like a group hug for your data operations, but with more ACID properties.

Executes a Redis transaction (MULTI/EXEC) using this object's connection context.

Provides atomic execution of multiple Redis commands with automatic connection management and operation mode enforcement. Uses the object's database and connection settings. Returns a MultiResult object for consistency with global methods.

Examples:

Performing a Database rain dance

transaction do |conn|
  conn.set("weather", "rainy")
  conn.set("mood", "melancholic")
end

Basic instance transaction

customer = Customer.new(custid: 'cust_123')
result = customer.transaction do |conn|
  conn.hset(customer.dbkey, 'name', 'John Doe')
  conn.hset(customer.dbkey, 'email', 'john@example.com')
  conn.hget(customer.dbkey, 'name')
end
result.successful?    # => true
result.results        # => ["OK", "OK", "John Doe"]

Using with object's database context

class Customer < Familia::Horreum
  logical_database 5  # Use database 5
  field :name
  field :email
end

customer = Customer.new(custid: 'cust_456')
result = customer.transaction do |conn|
  # Commands automatically execute in database 5
  conn.hset(customer.dbkey, 'status', 'active')
  conn.sadd('active_customers', customer.identifier)
end
result.successful?    # => true

Reentrant behavior with global transactions

customer = Customer.new(custid: 'cust_789')

# When called within a global transaction, reuses the transaction connection
result = Familia.transaction do |global_conn|
  global_conn.set('global_key', 'value')

  # This reuses the same transaction connection
  customer.transaction do |local_conn|
    local_conn.hset(customer.dbkey, 'updated', Time.now.to_i)
    'local_return_value'  # Returned directly in nested context
  end
end

Parameters:

  • block (Proc)

    The block containing Redis commands to execute atomically

Yields:

  • (conn)

    A block where you can perform your Database incantations.

  • (Redis)

    conn The Redis connection configured for transaction mode

Yield Parameters:

  • conn (Redis)

    A Database connection in multi mode.

Returns:

  • (MultiResult)

    Result object with success status and command results

Raises:

  • (Familia::OperationModeError)

    When called with incompatible connection handlers (e.g., FiberConnectionHandler or DefaultConnectionHandler that don't support transactions)

See Also:



138
139
140
141
# File 'lib/familia/horreum/connection.rb', line 138

def transaction(&)
  ensure_relatives_initialized!
  Familia::Connection::TransactionCore.execute_transaction(-> { dbclient }, &)
end