Skip to content

Redis Distributed Memory

Try it yourself! This example is available as an executable Jupyter notebook.

This example demonstrates using Redis-backed distributed memory so that agent conversation history survives pod restarts. By default agents use in-memory storage which is lost when a pod is recycled — Redis makes sessions durable across replicas and restarts.

Understanding the Flow

Prerequisites

  • KAOS operator installed (Installation Guide)
  • kaos-cli installed
  • Access to a Kubernetes cluster

When installing KAOS with --redis-enabled, Redis is deployed automatically and all agents default to Redis memory — no per-agent configuration needed:

kaos system install --redis-enabled --gateway-enabled --metallb-enabled --wait

This sets agentDefaults.memory.type=redis and agentDefaults.memory.redisUrl in the Helm values, so every agent created after install will use Redis memory by default.

Setup

For this walkthrough we'll configure Redis and memory explicitly so you can see all the moving parts. If you installed with --redis-enabled above, the global defaults already handle this and the explicit env vars below are not necessary.

python
import os
os.environ['NAMESPACE'] = 'redis-memory-example'
bash
kubectl create namespace $NAMESPACE 2>/dev/null || true
kubectl config set-context --current --namespace=$NAMESPACE

Step 1: Deploy Redis

Deploy a lightweight Redis instance in the namespace:

bash
kubectl apply -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:7-alpine
        ports:
        - containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  selector:
    app: redis
  ports:
  - port: 6379
    targetPort: 6379
EOF
bash
kubectl wait --for=condition=available deployment/redis --timeout=120s

Step 2: Create a ModelAPI

Create a ModelAPI in Proxy mode (we'll use mock responses so no real LLM needed):

bash
kaos modelapi deploy redis-api --mode Proxy --wait

Step 3: Create the Agent with Redis Memory

Deploy an agent with Redis memory enabled. The --env flags configure the memory backend explicitly:

bash
REDIS_URL="redis://redis.$NAMESPACE.svc.cluster.local:6379"

kaos agent deploy memory-agent \
    --modelapi redis-api \
    --model mock-model \
    --mock-response "I remember everything, even across restarts!" \
    --env "MEMORY_TYPE=redis" \
    --env "MEMORY_REDIS_URL=$REDIS_URL" \
    --instructions "You are a helpful assistant with persistent memory." \
    --expose \
    --wait

Step 4: Send a Message

Invoke the agent to create a conversation that gets stored in Redis:

bash
kaos agent invoke memory-agent --message "Remember this: the secret code is 42"

Step 5: Verify Memory is Stored

Check that the memory events were persisted:

python
import subprocess, json

result = subprocess.run(
    ["kubectl", "exec", "deploy/redis", "--",
     "redis-cli", "KEYS", "kaos:memory:*"],
    capture_output=True, text=True
)
print("Redis keys:", result.stdout.strip())

keys = [k for k in result.stdout.strip().split("\n") if k]
if len(keys) >= 2:
    print("SUCCESS: Memory events are stored in Redis!")
else:
    raise AssertionError(f"Expected Redis keys for session + events, got: {keys}")

Step 6: Restart the Agent Pod

Delete the agent pod to simulate a restart. The deployment controller will recreate it automatically:

bash
kubectl delete pods -l agent=memory-agent
kubectl rollout status deployment/agent-memory-agent --timeout=180s

Allow the new pod time to initialize and connect to Redis:

python
import subprocess, time

for attempt in range(24):
    ready = subprocess.run(
        ["kubectl", "get", "pods", "-l", "agent=memory-agent",
         "-o", "jsonpath={.items[0].status.conditions[?(@.type=='Ready')].status}"],
        capture_output=True, text=True
    )
    if ready.stdout.strip() == "True":
        print("Agent pod is ready!")
        break
    time.sleep(5)
else:
    debug = subprocess.run(["kubectl", "get", "pods", "-A"], capture_output=True, text=True)
    print(f"All pods:\n{debug.stdout}")
    raise AssertionError("Agent pod did not become ready after restart")

Step 7: Verify Memory Survived

After the pod restart, check that the conversation history is still available in Redis — this is the key benefit of distributed memory:

python
import subprocess

result = subprocess.run(
    ["kubectl", "exec", "deploy/redis", "--",
     "redis-cli", "KEYS", "kaos:memory:*"],
    capture_output=True, text=True
)

keys = [k for k in result.stdout.strip().split("\n") if k]
events_keys = [k for k in keys if ":events:" in k]

if events_keys:
    # Check the actual events in the list
    result = subprocess.run(
        ["kubectl", "exec", "deploy/redis", "--",
         "redis-cli", "LRANGE", events_keys[0], "0", "-1"],
        capture_output=True, text=True
    )
    events = result.stdout.strip().split("\n")
    event_types = []
    for e in events:
        try:
            import json
            data = json.loads(e)
            event_types.append(data.get("event_type", ""))
        except (json.JSONDecodeError, ValueError):
            pass

    if "user_message" in event_types:
        print(f"SUCCESS: Memory survived pod restart! Found {len(events)} events.")
        print(f"Event types: {event_types}")
    else:
        raise AssertionError(f"Expected user_message in events, got: {event_types}")
else:
    raise AssertionError(f"No events keys found in Redis after restart: {keys}")

How It Works

With Redis memory:

  • Sessions are stored as Redis hashes (HSET/HGETALL)
  • Events are stored as append-only lists (RPUSH/LRANGE) with automatic trimming
  • Session index tracks active sessions with sorted sets (ZADD/ZRANGE)
  • TTL is applied to session and event keys for automatic cleanup
  • All writes are pipelined for efficiency and consistency

Cleanup

bash
kubectl delete namespace $NAMESPACE --wait=false

Next Steps

Released under the Apache 2.0 License.