How Redis Caching Strategies Work for Session Management in Macro

The Macro platform uses Redis as a high-performance, in-memory store for transient session data across multiple microservices, enabling sub-millisecond access to OAuth pending states, document synchronization sessions, and cleanup tracking with automatic TTL-based expiration and atomic operations.

Redis caching strategies for session management are central to how the macro-inc/macro codebase handles short-lived state without burdening PostgreSQL. By leveraging Redis for pending OAuth flows, document sync sessions, and distributed worker coordination, the platform achieves horizontal scalability and consistent performance under load.

Pending OAuth Session Cache in MCP Auth Proxy

When a user initiates an OAuth authorization flow, the MCP Auth Proxy creates a unique broker session ID and stores temporary "pending" state in Redis. This pattern prevents incomplete authorizations from polluting the primary database.

In services/mcp_auth_proxy/src/outbound/redis.rs, the implementation uses a constant prefix combined with the session identifier to construct cache keys:

// Key pattern: "pending:{session_id}"
const PENDING_KEY_PREFIX: &str = "pending";

The put_pending function serializes the pending session record and writes it to Redis with an explicit TTL (time-to-live). This ensures stale flows automatically expire without manual cleanup:

let pending_key = format!("pending:{session_id}");
redis_conn.set_ex(pending_key, serialized_pending, 300).await?; // 5-minute TTL

Retrieval follows the inverse pattern via get operations that return Option<String>, allowing the proxy to detect expired or non-existent sessions gracefully:

let value: Option<String> = redis_conn.get(&pending_key).await?;
if let Some(json) = value {
    // Deserialize and continue OAuth flow; otherwise reject
}

Once the OAuth flow completes—successfully or with error—the pending key is explicitly deleted to free memory immediately.

Document Sync Session Storage

The Sync Service manages collaborative document editing sessions where clients frequently disconnect and reconnect. Storing volatile synchronization state in Redis allows rapid session resumption without re-querying the entire document from storage.

In services/sync-service/src/storage/mod.rs, the SessionStorage abstraction wraps a redis::Client connection to cache:

  • Snapshot metadata for active documents
  • Pending change deltas awaiting propagation
  • Client presence and cursor positions

This architecture keeps the sync service stateless; any instance can handle a reconnection by reading the session key from Redis. The implementation uses the async Redis client for microsecond-scale read/write operations, as implemented in the macro-inc/macro repo.

SHA Cleanup Worker: Atomic Set Operations

The SHA Cleanup Worker demonstrates advanced Redis patterns for distributed coordination. Multiple worker instances share a Redis-backed queue and progress tracker using atomic operations that guarantee consistency without locks.

Key utility functions in services/sha_cleanup_worker/src/service/redis/ include:

Function File Redis Command Purpose
remove_set_member remove_set_member.rs SREM Atomically remove processed SHA from pending set
increment increment.rs INCR Thread-safe counter for completed operations
get_set_members (set operations) SMEMBERS Retrieve all pending SHAs for batch processing

The atomic nature of these operations ensures that parallel workers never double-process the same SHA identifier. For example, the increment operation provides lock-free counting:

let completed: i64 = redis_conn.incr("sha_cleanup:processed_count", 1).await?;

Similarly, set membership operations enable efficient distributed work queues:

// Remove SHA from pending set (returns 1 if member existed, 0 otherwise)
let was_removed: i32 = redis_conn.srem("sha_cleanup:pending", sha_id).await?;

Local Development: Redis Container Orchestration

Consistent behavior across environments requires identical Redis configurations. The xtask_local tooling in tooling/xtask/crates/xtask_local/src/local/summary.rs automates this by spinning up a dedicated Redis container during local development and integration testing.

The container's connection URI is exposed through the REDIS_URI environment variable, which all services consume via their respective configuration layers. This approach ensures that:

  • Developers run the same caching semantics as production
  • Integration tests execute against a real Redis instance, not mocks
  • Service startup fails fast with clear errors if Redis is unreachable

Redis Caching Strategy Benefits

The Macro platform's session management architecture delivers specific operational advantages through disciplined Redis usage:

  • Automatic expiration via TTLs — Pending OAuth sessions and transient sync data evict themselves, eliminating garbage collection complexity
  • Atomic operations for safety — INCR, SREM, and similar commands prevent race conditions without application-level locking
  • Horizontal scalability — Stateless services share Redis as a single source of truth, allowing traffic distribution across any instance count
  • Consistent cross-service visibility — All microservices connect to the same Redis instance (or cluster), creating unified session state

Code Reference: Complete Redis Session Patterns

// Pattern 1: Pending OAuth session with TTL
let pending_key = format!("pending:{session_id}");
redis_conn.set_ex(&pending_key, json_payload, 300).await?;

// Pattern 2: Conditional session retrieval
match redis_conn.get::<_, Option<String>>(&pending_key).await? {
    Some(json) => serde_json::from_str(&json)?,
    None => return Err(SessionExpired),
}

// Pattern 3: Atomic counter for distributed tracking
let worker_processed: i64 = redis_conn.incr("cleanup:worker:count", 1).await?;

// Pattern 4: Set membership for work queue management
redis_conn.sadd("cleanup:pending_shas", new_sha).await?;
redis_conn.srem("cleanup:pending_shas", completed_sha).await?;
let remaining: Vec<String> = redis_conn.smembers("cleanup:pending_shas").await?;

Summary

  • Pending OAuth sessions in the MCP Auth Proxy use namespaced Redis keys with 5-minute TTLs to track incomplete authorization flows
  • Document sync sessions leverage the SessionStorage abstraction in the Sync Service for fast state recovery on client reconnection
  • Distributed cleanup coordination relies on atomic Redis set operations (SREM, INCR, SMEMBERS) to safely parallelize worker tasks
  • Development parity is enforced through xtask_local's automated Redis container provisioning and REDIS_URI configuration

Frequently Asked Questions

How does Macro prevent Redis session data from persisting indefinitely?

All pending session keys in the MCP Auth Proxy are written using set_ex with explicit TTL values (typically 300 seconds). The Sync Service similarly configures expiration on ephemeral sync metadata. This design eliminates the need for cron-based cleanup jobs and guarantees automatic eviction of abandoned sessions.

Can multiple Macro services share the same Redis instance safely?

Yes. The codebase uses distinct key prefixes (pending:, sync:, sha_cleanup:) to namespace data by domain. Additionally, Redis's single-threaded command execution ensures atomicity for operations like INCR and SREM, making concurrent access from multiple services safe without additional coordination.

What happens if Redis becomes unavailable during an active session?

Services are designed to fail fast when Redis connections drop. The MCP Auth Proxy returns errors for pending session lookups, forcing clients to restart OAuth flows. The Sync Service degrades gracefully by falling back to database-backed state reconstruction, though with higher latency until Redis recovers.

Why does Macro use Redis instead of PostgreSQL for these session types?

Redis provides sub-millisecond latency and native TTL support that PostgreSQL cannot match without complex partitioning and vacuum tuning. Session data is inherently ephemeral—frequently written, rarely read after completion, and safe to lose in outage scenarios—making Redis's memory-first architecture and optional persistence a purpose-fit choice.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →