Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Redis API

HydraCache can expose an optional Redis-compatible RESP edge for clients that already speak Redis.

This surface is a compatibility facade over HydraCache client-surface commands. It is not a promise that HydraCache is a full Redis replacement, and it does not add SQL/query semantics. Use it when Redis client interoperability is useful but the application still wants HydraCache ownership of cache data, TTLs, tags, diagnostics, and invalidation intent.

Crates

CrateRole
hydracache-redis-compatRESP2/RESP3 parsing, command translation, Redis-style responses, resource limits, and HydraCache extension commands.
hydracache-serverOptional TCP listener that serves the Redis RESP facade in the standalone daemon.

Application crates that only use the embedded HydraCache runtime do not need these crates.

Enable The Listener

The server disables the Redis facade by default. Enable it explicitly and keep it on a separate address from HTTP, admin, and cluster listeners.

$env:HYDRACACHE_REDIS_API_ENABLED = "true"
$env:HYDRACACHE_REDIS_ADDR = "127.0.0.1:6379"

For authenticated local or staging use:

$env:HYDRACACHE_REDIS_AUTH_REQUIRED = "true"
$env:HYDRACACHE_REDIS_AUTH_USERNAME = "default"
$env:HYDRACACHE_REDIS_AUTH_TOKEN_FILE = "C:\secrets\hydracache-redis-token.txt"

For rediss://, enable server TLS and the Redis TLS facade together:

$env:HYDRACACHE_TLS_ENABLED = "true"
$env:HYDRACACHE_TLS_CERT_PATH = "C:\certs\server.crt"
$env:HYDRACACHE_TLS_KEY_PATH = "C:\certs\server.key"
$env:HYDRACACHE_TLS_CA_PATH = "C:\certs\ca.crt"
$env:HYDRACACHE_REDIS_REDISS_ENABLED = "true"

HydraCache rejects rediss startup without complete TLS material.

Keyspace notifications are a separate off-by-default 0.68 capability:

$env:HYDRACACHE_REDIS_KEYSPACE_EVENTS_ENABLED = "true"
$env:HYDRACACHE_REDIS_MAX_EVENT_SUBSCRIPTIONS_PER_CONNECTION = "64"
$env:HYDRACACHE_REDIS_MAX_EVENT_SUBSCRIPTION_BYTES_PER_CONNECTION = "65536"

Use SUBSCRIBE/PSUBSCRIBE for __keyspace@0__:* or __keyevent@0__:*; use the matching unsubscribe command to release the live connection state. Admission is bounded by both unique subscription count and retained channel/pattern bytes. The event mode supports only cache-mutation notifications, not arbitrary Pub/Sub or PUBLISH.

Observe a native backend write from a Redis client

The server also projects successful native writes into this notification stream. Use the native typed namespace named redis: its physical redis:<key> prefix is stripped before the Redis channel is rendered. This explicit namespace fence prevents unrelated native cache entries from being exposed to Redis subscribers. Values never enter the event message or the RESP client-surface store, so a native-write notification does not make Redis GET return that native value.

This stream is at-most-once. Removing the final subscription releases the native receiver, and writes made while no subscription exists are not replayed after resubscription. Slow subscribers are disconnected on a detectable gap; they must reconnect, resubscribe, and repair state with ordinary reads. RESP/HC2 and native events retain their own source order, but no global order is claimed between those independent sources.

The example below is compiled by the documentation build. It starts the real RESP TCP listener, subscribes with redis-rs, writes with the ordinary native HydraCache API, and verifies the received Redis key event.

    let cache = HydraCache::local().build();
    let resp = Arc::new(
        RedisRespServer::new(
            Arc::new(ClientSurfaceState::new(ClientSurfaceLimits::default())?),
            RedisListenerConfig {
                keyspace_events: RedisKeyspaceEventConfig {
                    enabled: true,
                    ..RedisKeyspaceEventConfig::default()
                },
                ..RedisListenerConfig::default()
            },
        )?
        .with_native_cache_events(cache.clone()),
    );
    let listener = TcpListener::bind("127.0.0.1:0").await?;
    let address = listener.local_addr()?;
    let accepting = tokio::spawn(async move {
        while let Ok((stream, _)) = listener.accept().await {
            let resp = Arc::clone(&resp);
            tokio::spawn(async move {
                let _ = resp.serve_connection(stream).await;
            });
        }
    });

    // This is a normal Redis client using a normal keyspace subscription.
    let client = redis::Client::open(format!("redis://{address}/"))?;
    let mut pubsub = client.get_async_pubsub().await?;
    pubsub.subscribe("__keyevent@0__:set").await?;

    // The backend writes through the native HydraCache API. The `redis`
    // typed namespace is the explicit, non-leaking bridge to Redis key bytes.
    cache
        .typed::<String>("redis")
        .put("user:42", "Ada".to_owned(), CacheOptions::new())
        .await?;

    let message = tokio::time::timeout(Duration::from_secs(2), pubsub.on_message().next())
        .await?
        .ok_or("Redis subscription closed before the event")?;
    assert_eq!(message.get_channel_name(), "__keyevent@0__:set");
    assert_eq!(message.get_payload::<String>()?, "user:42");

    drop(pubsub);
    accepting.abort();

Supported Shape

The facade targets Redis string/cache-client interoperability:

  • connection and introspection basics such as PING, ECHO, HELLO, AUTH, CLIENT SETNAME, COMMAND, INFO, SELECT, and TYPE;
  • string and key operations such as GET, SET, MGET, MSET, DEL, and EXISTS;
  • TTL operations such as EXPIRE, PEXPIRE, PERSIST, TTL, and PTTL;
  • lock-oriented EVAL, EVALSHA, SCRIPT LOAD, and SCRIPT EXISTS for the supported compare-value lock scripts;
  • bounded SUBSCRIBE, UNSUBSCRIBE, PSUBSCRIBE, and PUNSUBSCRIBE for off-by-default keyspace notifications; and
  • HydraCache extension commands such as HC.STATS, HC.DIAGNOSTICS, HC.INVALIDATE, HC.NAMESPACE, HC.TAG, HC.SETTAGS, and HC.INVALIDATE_TAG.

Unsupported Redis data structures or broad server features should be treated as outside the facade. For example, hash commands are not the goal of this surface.

Client Examples

Any Redis client can use the facade for the supported command subset.

PING
SET user:42 Ada PX 60000
GET user:42
MSET user:43 Grace user:44 Linus
MGET user:42 user:43 user:44
TTL user:42
DEL user:44

HydraCache-specific tags are available through extension commands:

HC.SETTAGS user:42 user:42 users
HC.INVALIDATE_TAG users
HC.STATS
HC.DIAGNOSTICS

Use tags when Redis-facing clients should participate in the same invalidation model as native HydraCache code.

Boundaries

The Redis API is best for interoperability, migration seams, smoke tests, and operational probes. Prefer the native Rust API when application code can call HydraCache directly because native calls preserve typed values, loader boundaries, single-flight behavior, and compile-time policy structure.

Review these boundaries before enabling the facade:

  • RESP resource limits protect frame size, array length, bulk string size, read buffer size, and idle connections.
  • AUTH is optional but should be required for any shared environment.
  • The listener address must not conflict with HTTP, cluster, or admin addresses.
  • Redis keys map into the Redis namespace of the HydraCache client surface.
  • Keyspace notifications are node-local, metadata-only, at-most-once hints. A lagging client is disconnected and must reconnect, resubscribe, and repair state with ordinary reads.
  • Redis clients send bytes, not typed Rust values; typed decoding remains a native API concern.

Use Redis compatibility to meet existing clients where they are. Use HydraCache semantics to decide what should be cached and invalidated.