# How Redis Caching Strategies Work for Session Management in Macro

> Discover how Macro uses Redis caching strategies for efficient session management. Learn about sub-millisecond access to transient data and automatic expiration for enhanced performance.

- Repository: [Macro/macro](https://github.com/macro-inc/macro)
- Tags: deep-dive
- Published: 2026-08-15

---

**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](https://github.com/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`](https://github.com/macro-inc/macro/blob/main/services/mcp_auth_proxy/src/outbound/redis.rs), the implementation uses a constant prefix combined with the session identifier to construct cache keys:

```rust
// 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:

```rust
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:

```rust
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`](https://github.com/macro-inc/macro/blob/main/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](https://github.com/macro-inc/macro/blob/main/services/sync-service/src/storage/mod.rs).

## 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`](https://github.com/macro-inc/macro/blob/main/remove_set_member.rs) | `SREM` | Atomically remove processed SHA from pending set |
| `increment` | [`increment.rs`](https://github.com/macro-inc/macro/blob/main/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:

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

```

Similarly, set membership operations enable efficient distributed work queues:

```rust
// 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`](https://github.com/macro-inc/macro/blob/main/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

```rust
// 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.