class

Redis::ReplicationClient

Inherits Redis::Commands::Immediate < Redis::Commands < Redis::Commands::Vector < Redis::Commands::HyperLogLog < Redis::Commands::Geo < Redis::Commands::Stream < Redis::Commands::SortedSet < Redis::Commands::Set < Redis::Commands::List < Redis::Commands::Hash < Reference < Object

If you're using Redis replication, you can use ReplicationClient to send read commands to replicas and reduce load on the primary. This can be important when your Redis primary is CPU-bound.

The commands that will be routed to replicas are listed in Redis::READ_ONLY_COMMANDS.

NOTE: Redis replication does not provide consistency guarantees. Every mechanism in Redis to improve consistency, such as WAIT, is best-effort, but not guaranteed. If you require strong consistency from Redis, stick to using Redis::Client. if you require strong consistency but your Redis primary is CPU-bound, you may need to either choose between consistency and performance or move that workload out of Redis.

This client is useful for operations where strong consistency isn't typically needed, such as caching, full-text search with Redis::FullText#search, querying time-series data with Redis::TimeSeries#mrange, checking the current state of larger data structures without blocking the primary, etc.

Explicitly routing commands to a primary or replica

This class provides on_primary and on_replica methods to ensure your command is routed to the server type you want. This is useful in several scenarios:

  • you want to ensure you retrieve a value that is consistent with the state of the primary server — for example a value that changes frequently and you need the canonical state for observability purposes
  • a read-only command is routed to a primary because this client does not yet know about it
    • You can add commands to Redis::READ_ONLY_COMMANDS in one-off cases
    • Feel free to open an issue or pull request to add it, as well

Topology changes

If the replication topology changes (for example, new replicas are added, existing ones removed, or the primary failed over), ReplicationClient will automatically pick up the changes. You can set how often it checks for these changes with the topology_ttl argument to the constructor or leave it at its default of 10 seconds.

Constants

Log = ::Log.for(self)

Constructors

new(entrypoint : URI, topology_ttl : Time::Span = 10.seconds)

Have the ReplicationClient discover the master and replicas on its own when given the URI of a single entrypoint. The cluster topology will be refreshed with a max staleness of topology_ttl.

redis = Redis::ReplicationClient.new(
Source
new(master_uri : URI, replica_uris : Array(URI), topology_ttl : Time::Span = 10.seconds)

Initialize the client with known master and replica URIs, keeping the toplogy up to date with at most topology_ttl staleness. If you don't wish to keep the replication topology up to date, you can simply set topology_ttl to 0.seconds.

Source

Instance methods

close

Close all connections to both the primary and all replicas.

Source
closed?

Returns true if this ReplicationClient has been explicitly closed, false otherwise.

Source
on_master

Alias of on_primary.

Source
on_primary

Route one or more commands to the primary to avoid consistency issues arising from replication latency.

require "redis/replication_client"

redis = Redis::ReplicationClient.new

redis.incr "counter"
value = redis.on_primary &.get("counter")

This is useful for pipelining commands or executing transactions:

redis.on_primary &.transaction do |txn|
  txn.incr "counter:#{queue}"
  txn.sadd "queues", queue
  txn.lpush "queue:#{queue}", job_data
end

… which is shorthand for this and removes the need for nesting blocks:

redis.on_primary do |primary|
  primary.transaction do |txn|
    txn.incr "counter:#{queue}"
    txn.sadd "queues", queue
    txn.lpush "queue:#{queue}", job_data
  end
end

If you need to route many commands to the primary without necessarily pipelining or opening transactions, you can omit the &.transaction and call methods directly on the primary's Redis::Client in the block:

redis.on_primary do |primary|
  counter = primary.incr "counter:#{queue}"
  primary.sadd "queues", queue
end

NOTE: The object yielded to the block is a Redis::Client, but if you try to use it outside the block you may run into errors because the replication topology could change, in which case this Redis::Client might not be the primary anymore.

Source
on_replica

Route one or more commands to replicas. This should rarely be necessary since read-only commands (which can only be executed on replicas) are automatically routed to replicas, but if it's a command this shard does not know about (see Redis::READ_ONLY_COMMANDS) this may be necessary. Alternatively, you can shovel additional commands into Redis::READ_ONLY_COMMANDS to avoid having to perform this explicit routing.

Source
run(command full_command)

Execute the given command and return the result from the server. Commands must be an Enumerable and its size method must be re-entrant.

run({"set", "foo", "bar"})
Source
topology_ttl
Source

Nested types