Redis Cluster

If your infrastructure contains a Redis Cluster, coredis provides a RedisCluster client than can be used with the same API as Redis but with awareness of routing the operations to the appropriate node in the cluster.

Request routing

For operations that operate on single keys the RedisCluster client simply routes the command to the appropriate node that is serving the slot that contains the key.

There are other categories of operations that cannot simply be used with redis cluster by just routing it to the appropriate node by a single key (such as commands that don’t contain keys, or contain multiple keys). coredis uses a few routing strategies detailed below, to handle some of these operations so that the methods in RedisCluster can be used in a consistent manner.

Danger

For write operations that interact with multiple slots, this means that even if coredis is able to distribute the operation through sub requests - the actual atomicity of the request is lost as a failure on one node will leave the successful nodes in an inconsistent state. If the risk of this scenario is unacceptable the automatic routing for cross slot commands can be disabled by setting non_atomic_cross_slot to False.

Commands routed to all nodes in the cluster

Server commands
coredis.RedisCluster.acl_deluser()

The result is the first response if all responses are consistent

coredis.RedisCluster.acl_load()

The result is the first response if all responses are consistent

coredis.RedisCluster.acl_save()

The result is the first response if all responses are consistent

coredis.RedisCluster.acl_setuser()

The result is the first response if all responses are consistent

coredis.RedisCluster.config_resetstat()

The result is True if all responses are True

coredis.RedisCluster.config_set()

The result is True if all responses are True

coredis.RedisCluster.memory_purge()

The result is True if all responses are True

coredis.RedisCluster.module_load()

The result is True if all responses are True

coredis.RedisCluster.module_loadex()

The result is True if all responses are True

coredis.RedisCluster.module_unload()

The result is True if all responses are True

coredis.RedisCluster.save()

The result is the first response if all responses are consistent

Cluster commands
coredis.RedisCluster.cluster_saveconfig()

The result is True if all responses are True

Connection commands
coredis.RedisCluster.echo()

The result is the first response if all responses are consistent

Pubsub commands
coredis.RedisCluster.pubsub_channels()

The result is the union of the results

coredis.RedisCluster.pubsub_numsub()

The result is the merged mapping

coredis.RedisCluster.pubsub_shardchannels()

The result is the union of the results

coredis.RedisCluster.pubsub_shardnumsub()

The result is the merged mapping

Scripting commands
coredis.RedisCluster.script_flush()

The result is True if all responses are True

coredis.RedisCluster.script_load()

The result is the first response if all responses are consistent

Commands routed to all primaries in the cluster

Server commands
coredis.RedisCluster.flushall()

The result is the first response if all responses are consistent

coredis.RedisCluster.flushdb()

The result is the first response if all responses are consistent

Scripting commands
coredis.RedisCluster.function_delete()

The result is the first response if all responses are consistent

coredis.RedisCluster.function_flush()

The result is the first response if all responses are consistent

coredis.RedisCluster.function_kill()

The result is the first response that is not an error

coredis.RedisCluster.function_load()

The result is the first response if all responses are consistent

coredis.RedisCluster.function_restore()

The result is the first response if all responses are consistent

coredis.RedisCluster.script_exists()

The result is the logical AND of all responses

coredis.RedisCluster.script_kill()

The result is the first response that is not an error

Generic commands
coredis.RedisCluster.keys()

The result is the union of the results

Connection commands
coredis.RedisCluster.ping()

The result is the first response if all responses are consistent

Search commands
coredis.modules.Search.config_set()

The result is the first response if all responses are consistent

coredis.modules.Search.list()

The result is the union of the results

Timeseries commands
coredis.modules.TimeSeries.mget()

The result is the merged mapping

coredis.modules.TimeSeries.mrange()

The result is the merged mapping

coredis.modules.TimeSeries.mrevrange()

The result is the merged mapping

coredis.modules.TimeSeries.queryindex()

The result is the union of the results

Commands routed to the nodes serving the keys in the command

Generic commands
coredis.RedisCluster.delete()

The result is the sum of results

coredis.RedisCluster.exists()

The result is the sum of results

coredis.RedisCluster.touch()

The result is the sum of results

coredis.RedisCluster.unlink()

The result is the sum of results

String commands
coredis.RedisCluster.mget()

The result is the concatenations of the results

coredis.RedisCluster.mset()

The result is True if all responses are True

Json commands
coredis.modules.Json.mget()

The result is the concatenations of the results

coredis.modules.Json.mset()

The result is True if all responses are True

Commands routed to a random node in the cluster

Server commands
coredis.RedisCluster.acl_cat()

The result is the response from the node

coredis.RedisCluster.acl_dryrun()

The result is the response from the node

coredis.RedisCluster.acl_genpass()

The result is the response from the node

coredis.RedisCluster.acl_getuser()

The result is the response from the node

coredis.RedisCluster.acl_list()

The result is the response from the node

coredis.RedisCluster.acl_users()

The result is the response from the node

coredis.RedisCluster.acl_whoami()

The result is the response from the node

coredis.RedisCluster.command()

The result is the response from the node

coredis.RedisCluster.command_count()

The result is the response from the node

coredis.RedisCluster.command_docs()

The result is the response from the node

coredis.RedisCluster.command_getkeys()

The result is the response from the node

coredis.RedisCluster.command_getkeysandflags()

The result is the response from the node

coredis.RedisCluster.command_info()

The result is the response from the node

coredis.RedisCluster.command_list()

The result is the response from the node

coredis.RedisCluster.info()

The result is the response from the node

coredis.RedisCluster.module_list()

The result is the response from the node

Cluster commands
coredis.RedisCluster.cluster_count_failure_reports()

The result is the response from the node

coredis.RedisCluster.cluster_info()

The result is the response from the node

coredis.RedisCluster.cluster_keyslot()

The result is the response from the node

coredis.RedisCluster.cluster_meet()

The result is the response from the node

coredis.RedisCluster.cluster_nodes()

The result is the response from the node

coredis.RedisCluster.cluster_replicas()

The result is the response from the node

coredis.RedisCluster.cluster_shards()

The result is the response from the node

coredis.RedisCluster.cluster_slaves()

The result is the response from the node

coredis.RedisCluster.cluster_slots()

The result is the response from the node

Scripting commands
coredis.RedisCluster.function_dump()

The result is the response from the node

coredis.RedisCluster.function_list()

The result is the response from the node

coredis.RedisCluster.function_stats()

The result is the response from the node

Pubsub commands
coredis.RedisCluster.publish()

The result is the response from the node

Generic commands
coredis.RedisCluster.randomkey()

The result is the response from the node

Search commands
coredis.modules.Search.config_get()

The result is the response from the node

Commands routed to node(s) based on the slot id(s) in the command arguments

Cluster commands
coredis.RedisCluster.cluster_countkeysinslot()

The result is the response from the node

coredis.RedisCluster.cluster_delslots()

The result is True if all responses are True

coredis.RedisCluster.cluster_delslotsrange()

The result is True if all responses are True

coredis.RedisCluster.cluster_getkeysinslot()

The result is the response from the node

Replication

coredis supports ensuring synchronous replication of writes using the WAIT command. This is abstracted away with the ensure_replication() context manager.

The following example will ensure that the SET is replicated to atleast 2 replicas within 100 milliseconds (default value of timeout_ms), else raise a ReplicationError:

import asyncio
from coredis import RedisCluster
from coredis.connection import TCPLocation

async def test():
    async with RedisCluster(startup_nodes=[TCPLocation("127.0.0.1", 7000)]) as client:
        with client.ensure_replication(replicas=2):
            await client.set("fubar", 1)

asyncio.run(test())