Skip to content

Commit 11235ce

Browse files
committed
100% documentation coverage.
1 parent 2c1c4cd commit 11235ce

File tree

11 files changed

+209
-2
lines changed

11 files changed

+209
-2
lines changed

lib/async/redis.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66

77
require_relative "redis/version"
88
require_relative "redis/client"
9+
require_relative "redis/endpoint"
910

1011
require_relative "redis/cluster_client"
1112
require_relative "redis/sentinel_client"
13+
14+
# @namespace
15+
module Async
16+
# @namespace
17+
module Redis
18+
end
19+
end

lib/async/redis/client.rb

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,18 @@ module Redis
2323
# Legacy.
2424
ServerError = ::Protocol::Redis::ServerError
2525

26+
# A Redis client that provides connection pooling and context management.
2627
class Client
2728
include ::Protocol::Redis::Methods
2829

30+
# Methods module providing Redis-specific functionality.
2931
module Methods
32+
# Subscribe to one or more channels for pub/sub messaging.
33+
# @parameter channels [Array(String)] The channels to subscribe to.
34+
# @yields {|context| ...} If a block is given, it will be executed within the subscription context.
35+
# @parameter context [Context::Subscribe] The subscription context.
36+
# @returns [Object] The result of the block if block given.
37+
# @returns [Context::Subscribe] The subscription context if no block given.
3038
def subscribe(*channels)
3139
context = Context::Subscribe.new(@pool, channels)
3240

@@ -39,6 +47,11 @@ def subscribe(*channels)
3947
end
4048
end
4149

50+
# Execute commands within a Redis transaction.
51+
# @yields {|context| ...} If a block is given, it will be executed within the transaction context.
52+
# @parameter context [Context::Transaction] The transaction context.
53+
# @returns [Object] The result of the block if block given.
54+
# @returns [Context::Transaction] Else if no block is given, returns the transaction context.
4255
def transaction(&block)
4356
context = Context::Transaction.new(@pool)
4457

@@ -53,6 +66,11 @@ def transaction(&block)
5366

5467
alias multi transaction
5568

69+
# Execute commands in a pipeline for improved performance.
70+
# @yields {|context| ...} If a block is given, it will be executed within the pipeline context.
71+
# @parameter context [Context::Pipeline] The pipeline context.
72+
# @returns [Object] The result of the block if block given.
73+
# @returns [Context::Pipeline] The pipeline context if no block given.
5674
def pipeline(&block)
5775
context = Context::Pipeline.new(@pool)
5876

@@ -68,6 +86,9 @@ def pipeline(&block)
6886
# Deprecated.
6987
alias nested pipeline
7088

89+
# Execute a Redis command directly.
90+
# @parameter arguments [Array] The command and its arguments.
91+
# @returns [Object] The response from the Redis server.
7192
def call(*arguments)
7293
@pool.acquire do |connection|
7394
connection.write_request(arguments)
@@ -78,25 +99,37 @@ def call(*arguments)
7899
end
79100
end
80101

102+
# Close the client and all its connections.
81103
def close
82104
@pool.close
83105
end
84106
end
85107

86108
include Methods
87109

110+
# Create a new Redis client.
111+
# @parameter endpoint [Endpoint] The Redis endpoint to connect to.
112+
# @parameter protocol [Protocol] The protocol to use for communication.
113+
# @parameter options [Hash] Additional options for the connection pool.
88114
def initialize(endpoint = Endpoint.local, protocol: endpoint.protocol, **options)
89115
@endpoint = endpoint
90116
@protocol = protocol
91117

92118
@pool = make_pool(**options)
93119
end
94120

121+
# @attribute [Endpoint] The Redis endpoint.
95122
attr :endpoint
123+
124+
# @attribute [Protocol] The communication protocol.
96125
attr :protocol
97126

98-
# @return [client] if no block provided.
99-
# @yield [client, task] yield the client in an async task.
127+
# Open a Redis client and optionally yield it in an async task.
128+
# @yields {|client, task| ...} If a block is given, yield the client in an async task.
129+
# @parameter client [Client] The Redis client instance.
130+
# @parameter task [Async::Task] The async task.
131+
# @returns [Client] The client if no block provided.
132+
# @returns [Object] The result of the block if block given.
100133
def self.open(*arguments, **options, &block)
101134
client = self.new(*arguments, **options)
102135

lib/async/redis/cluster_client.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,39 @@
99

1010
module Async
1111
module Redis
12+
# A Redis cluster client that manages multiple Redis instances and handles cluster operations.
1213
class ClusterClient
14+
# Raised when cluster configuration cannot be reloaded.
1315
class ReloadError < StandardError
1416
end
1517

18+
# Raised when no nodes are found for a specific slot.
1619
class SlotError < StandardError
1720
end
1821

1922
Node = Struct.new(:id, :endpoint, :role, :health, :client)
2023

24+
# A map that stores ranges and their associated values for efficient lookup.
2125
class RangeMap
26+
# Initialize a new RangeMap.
2227
def initialize
2328
@ranges = []
2429
end
2530

31+
# Add a range-value pair to the map.
32+
# @parameter range [Range] The range to map.
33+
# @parameter value [Object] The value to associate with the range.
34+
# @returns [Object] The added value.
2635
def add(range, value)
2736
@ranges << [range, value]
2837

2938
return value
3039
end
3140

41+
# Find the value associated with a key within any range.
42+
# @parameter key [Object] The key to find.
43+
# @yields {...} Block called if no range contains the key.
44+
# @returns [Object] The value if found, result of block if given, or nil.
3245
def find(key)
3346
@ranges.each do |range, value|
3447
return value if range.include?(key)
@@ -41,12 +54,16 @@ def find(key)
4154
return nil
4255
end
4356

57+
# Iterate over all values in the map.
58+
# @yields {|value| ...} Block called for each value.
59+
# @parameter value [Object] The value from the range-value pair.
4460
def each
4561
@ranges.each do |range, value|
4662
yield value
4763
end
4864
end
4965

66+
# Clear all ranges from the map.
5067
def clear
5168
@ranges.clear
5269
end
@@ -61,6 +78,13 @@ def initialize(endpoints, **options)
6178
@shards = nil
6279
end
6380

81+
# Execute a block with clients for the given keys, grouped by cluster slot.
82+
# @parameter keys [Array] The keys to find clients for.
83+
# @parameter role [Symbol] The role of nodes to use (:master or :slave).
84+
# @parameter attempts [Integer] Number of retry attempts for cluster errors.
85+
# @yields {|client, keys| ...} Block called for each client-keys pair.
86+
# @parameter client [Client] The Redis client for the slot.
87+
# @parameter keys [Array] The keys handled by this client.
6488
def clients_for(*keys, role: :master, attempts: 3)
6589
slots = slots_for(keys)
6690

@@ -83,6 +107,10 @@ def clients_for(*keys, role: :master, attempts: 3)
83107
end
84108
end
85109

110+
# Get a client for a specific slot.
111+
# @parameter slot [Integer] The cluster slot number.
112+
# @parameter role [Symbol] The role of node to get (:master or :slave).
113+
# @returns [Client] The Redis client for the slot.
86114
def client_for(slot, role = :master)
87115
unless @shards
88116
reload_cluster!
@@ -203,6 +231,9 @@ def slot_for(key)
203231
return crc16(key) % HASH_SLOTS
204232
end
205233

234+
# Calculate the hash slots for multiple keys.
235+
# @parameter keys [Array] The keys to calculate slots for.
236+
# @returns [Hash] A hash mapping slot numbers to arrays of keys.
206237
def slots_for(keys)
207238
slots = Hash.new{|hash, key| hash[key] = []}
208239

lib/async/redis/context/generic.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,45 @@
88

99
module Async
1010
module Redis
11+
# @namespace
1112
module Context
13+
# Base class for Redis command execution contexts.
1214
class Generic
15+
# Initialize a new generic context.
16+
# @parameter pool [Pool] The connection pool to use.
17+
# @parameter arguments [Array] Additional arguments for the context.
1318
def initialize(pool, *arguments)
1419
@pool = pool
1520
@connection = pool.acquire
1621
end
1722

23+
# Close the context and release the connection back to the pool.
1824
def close
1925
if @connection
2026
@pool.release(@connection)
2127
@connection = nil
2228
end
2329
end
2430

31+
# Write a Redis command request to the connection.
32+
# @parameter command [String] The Redis command.
33+
# @parameter arguments [Array] The command arguments.
2534
def write_request(command, *arguments)
2635
@connection.write_request([command, *arguments])
2736
end
2837

38+
# Read a response from the Redis connection.
39+
# @returns [Object] The Redis response.
2940
def read_response
3041
@connection.flush
3142

3243
return @connection.read_response
3344
end
3445

46+
# Execute a Redis command and return the response.
47+
# @parameter command [String] The Redis command.
48+
# @parameter arguments [Array] The command arguments.
49+
# @returns [Object] The Redis response.
3550
def call(command, *arguments)
3651
write_request(command, *arguments)
3752

lib/async/redis/context/pipeline.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ module Context
1414
class Pipeline < Generic
1515
include ::Protocol::Redis::Methods
1616

17+
# A synchronous wrapper for pipeline operations that executes one command at a time.
1718
class Sync
1819
include ::Protocol::Redis::Methods
1920

21+
# Initialize a new sync wrapper.
22+
# @parameter pipeline [Pipeline] The pipeline to wrap.
2023
def initialize(pipeline)
2124
@pipeline = pipeline
2225
end
@@ -31,6 +34,8 @@ def call(...)
3134
end
3235
end
3336

37+
# Initialize a new pipeline context.
38+
# @parameter pool [Pool] The connection pool to use.
3439
def initialize(pool)
3540
super(pool)
3641

@@ -46,6 +51,9 @@ def flush(count = 0)
4651
end
4752
end
4853

54+
# Collect all pending responses.
55+
# @yields {...} Optional block to execute while collecting responses.
56+
# @returns [Array] Array of all responses if no block given.
4957
def collect
5058
if block_given?
5159
flush
@@ -55,6 +63,8 @@ def collect
5563
@count.times.map{read_response}
5664
end
5765

66+
# Get a synchronous wrapper for this pipeline.
67+
# @returns [Sync] A synchronous wrapper that executes commands immediately.
5868
def sync
5969
@sync ||= Sync.new(self)
6070
end
@@ -73,6 +83,8 @@ def call(command, *arguments)
7383
return nil
7484
end
7585

86+
# Read a response from the pipeline.
87+
# @returns [Object] The next response in the pipeline.
7688
def read_response
7789
if @count > 0
7890
@count -= 1
@@ -82,6 +94,7 @@ def read_response
8294
end
8395
end
8496

97+
# Close the pipeline and flush all pending responses.
8598
def close
8699
flush
87100
ensure

lib/async/redis/context/subscribe.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,38 @@
99
module Async
1010
module Redis
1111
module Context
12+
# Context for Redis pub/sub subscription operations.
1213
class Subscribe < Generic
1314
MESSAGE = "message"
1415

16+
# Initialize a new subscription context.
17+
# @parameter pool [Pool] The connection pool to use.
18+
# @parameter channels [Array(String)] The channels to subscribe to.
1519
def initialize(pool, channels)
1620
super(pool)
1721

1822
subscribe(channels)
1923
end
2024

25+
# Close the subscription context.
2126
def close
2227
# There is no way to reset subscription state. On Redis v6+ you can use RESET, but this is not supported in <= v6.
2328
@connection&.close
2429

2530
super
2631
end
2732

33+
# Listen for the next message from subscribed channels.
34+
# @returns [Array] The next message response, or nil if connection closed.
2835
def listen
2936
while response = @connection.read_response
3037
return response if response.first == MESSAGE
3138
end
3239
end
3340

41+
# Iterate over all messages from subscribed channels.
42+
# @yields {|response| ...} Block called for each message.
43+
# @parameter response [Array] The message response.
3444
def each
3545
return to_enum unless block_given?
3646

@@ -39,11 +49,15 @@ def each
3949
end
4050
end
4151

52+
# Subscribe to additional channels.
53+
# @parameter channels [Array(String)] The channels to subscribe to.
4254
def subscribe(channels)
4355
@connection.write_request ["SUBSCRIBE", *channels]
4456
@connection.flush
4557
end
4658

59+
# Unsubscribe from channels.
60+
# @parameter channels [Array(String)] The channels to unsubscribe from.
4761
def unsubscribe(channels)
4862
@connection.write_request ["UNSUBSCRIBE", *channels]
4963
@connection.flush

lib/async/redis/context/transaction.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,22 @@
99
module Async
1010
module Redis
1111
module Context
12+
# Context for Redis transaction operations using MULTI/EXEC.
1213
class Transaction < Pipeline
14+
# Initialize a new transaction context.
15+
# @parameter pool [Pool] The connection pool to use.
16+
# @parameter arguments [Array] Additional arguments for the transaction.
1317
def initialize(pool, *arguments)
1418
super(pool)
1519
end
1620

21+
# Begin a transaction block.
1722
def multi
1823
call("MULTI")
1924
end
2025

26+
# Watch keys for changes during the transaction.
27+
# @parameter keys [Array(String)] The keys to watch.
2128
def watch(*keys)
2229
sync.call("WATCH", *keys)
2330
end
@@ -27,6 +34,7 @@ def execute
2734
sync.call("EXEC")
2835
end
2936

37+
# Discard all queued commands in the transaction.
3038
def discard
3139
sync.call("DISCARD")
3240
end

0 commit comments

Comments
 (0)