Skip to content

Redis and Valkey

RedisProvider serves every kind: Lock, LeaderElection, Schedule, TTLCache, RateLimiter, and CircuitBreaker. It wraps a redis.asyncio client and opens the pool on __aenter__.

from grelmicro import Grelmicro
from grelmicro.providers.redis import RedisProvider

redis = RedisProvider("redis://localhost:6379/0")

micro = Grelmicro(uses=[redis])

Install the redis extra first: pip install "grelmicro[redis]".

Environment variables

Construct the provider with no arguments and it reads its connection from the environment. These reads need no GREL_ENV_LOAD, they are the provider's own connection variables:

Environment variable Description Default
REDIS_URL Full Redis URL (e.g. redis://localhost:6379/0)
REDIS_HOST Redis hostname
REDIS_PORT Redis port 6379
REDIS_DB Redis database number 0
REDIS_PASSWORD Redis password
REDIS_SENTINEL_PASSWORD Sentinel requirepass, for redis+sentinel:// only

Set either REDIS_URL or REDIS_HOST, not both. Pass env_prefix= for a different prefix, see Recipe 2.

Construction forms

RedisProvider("redis://localhost:6379")      # positional URL
RedisProvider(url="redis://...")             # keyword URL
RedisProvider(host="x", port=6379, db=0)     # decomposed kwargs
RedisProvider()                              # env-driven (REDIS_*)
RedisProvider(env_prefix="CACHE_REDIS_")     # custom env prefix
RedisProvider(env_load=False)                # kwargs only, no env
RedisProvider.from_config(RedisConfig(...))  # from a config object
RedisProvider.from_client(client)            # bring-your-own client

Sentinel and Cluster

RedisProvider switches topology from the URL scheme. The scheme rides the same url field, so REDIS_URL alone selects standalone, Sentinel, or Cluster with no other code change.

Standalone stays as before:

RedisProvider("redis://localhost:6379/0")

Sentinel lists the Sentinel hosts in the authority. The first path segment is the master service name. An optional second segment is the database index.

RedisProvider("redis+sentinel://host1:26379,host2:26379/mymaster/0")

Cluster lists the seed nodes. The client discovers the rest of the topology from them.

RedisProvider("redis+cluster://host1:6379,host2:6379")

Authenticated Sentinels

Sentinel servers often run with their own requirepass, and the Bitnami Redis chart turns that on by default. That password is separate from the data password, and both fit in the environment:

REDIS_URL=redis+sentinel://sentinel-0:26379,sentinel-1:26379/mymaster/0
REDIS_PASSWORD=...
REDIS_SENTINEL_PASSWORD=...
provider = RedisProvider()

It applies only when set. The data password is never reused for the Sentinel connections, because AUTH against a server without requirepass fails, which would break every deployment whose Sentinels are unauthenticated.

It also applies only to a redis+sentinel:// URL. Setting it alongside any other scheme warns rather than passing silently, since one environment often serves several services and only some of them talk to Sentinel.

The same value is available as sentinel_password= on the constructor and on RedisConfig.

Credentials in the URL userinfo apply to both the Sentinel connections and the data connections. Use the factory methods when you need to pass other Sentinel connection settings:

RedisProvider.sentinel(
    sentinels=[("host1", 26379), ("host2", 26379)],
    service_name="mymaster",
    db=0,
    password="data-password",
    sentinel_kwargs={"password": "sentinel-password"},
)

RedisProvider.cluster(
    nodes=[("host1", 6379), ("host2", 6379)],
    password="cluster-password",
)

safe_url and repr() redact the password for every scheme, including the multi-host forms.

Failover on Sentinel

The Sentinel client re-resolves the master when it changes. During that brief window an in-flight command can error. Wrap the call in the resilience patterns (retry and circuit breaker) to ride through the failover.

The hash-tag rule on Cluster

A Redis Cluster shards keys across slots by a hash of the key. A command or script that touches several keys must keep them in one slot, or the cluster rejects it as a cross-slot error.

The cache adapter and the lock adapter both run multi-key operations. On Cluster, give their prefix a hash tag so every key they touch lands in one slot. A hash tag is any substring in braces: the cluster hashes only what is inside the first {...}.

provider = RedisProvider("redis+cluster://host1:6379,host2:6379")
cache = provider.cache(prefix="{myapp}cache")
lock = provider.lock(prefix="{myapp}")

Without a hash tag, the adapter raises a ValueError at construction that names the fix. Standalone and Sentinel need no hash tag, since every key lives on one server. The rate limiter, circuit breaker, schedule, and leader-election adapters touch one key per call and work on Cluster as is.

Valkey

ValkeyProvider is a subclass of RedisProvider. It connects to a Valkey server using the valkey-py client (valkey.asyncio) and serves the same adapter set.

Install the valkey extra before using it:

pip install "grelmicro[valkey]"
from grelmicro import Grelmicro
from grelmicro.providers.valkey import ValkeyProvider

valkey = ValkeyProvider("valkey://localhost:6379/0")

micro = Grelmicro(uses=[valkey])

Set VALKEY_URL (or VALKEY_HOST + VALKEY_PORT + VALKEY_DB + VALKEY_PASSWORD) for env-driven construction.

Construction forms:

ValkeyProvider("redis://localhost:6379")     # positional URL
ValkeyProvider(url="redis://...")            # keyword URL
ValkeyProvider(host="x", port=6379, db=0)   # decomposed kwargs
ValkeyProvider()                             # env-driven (VALKEY_*)
ValkeyProvider(env_prefix="CACHE_VALKEY_")  # custom env prefix
ValkeyProvider(env_load=False)              # kwargs only, no env
ValkeyProvider.from_config(ValkeyConfig(...))  # from a config object
ValkeyProvider.from_client(client)           # bring-your-own client

ValkeyProvider also reads Valkey's own schemes, so a deployment can name the server it runs: valkey://, valkeys://, valkey+sentinel://, and valkey+cluster:// work wherever the redis spellings do, in the constructor, in VALKEY_URL, and in ValkeyConfig. RedisProvider and RedisConfig keep the redis schemes only.

ValkeyConfig carries the same fields as RedisConfig, so ValkeyProvider.from_config() takes either one.

ValkeyProvider reads the same redis+sentinel:// and redis+cluster:// schemes as RedisProvider and builds the Valkey Sentinel and Cluster clients. The factory methods ValkeyProvider.sentinel(...) and ValkeyProvider.cluster(...) and the Cluster hash-tag rule apply the same way.