Skip to main content

Redis Store

High-performance store using Redis with TTL support.

Installation​

npm install @saga-bus/store-redis ioredis

Basic Usage​

import { RedisSagaStore } from '@saga-bus/store-redis';

const store = new RedisSagaStore({
url: 'redis://localhost:6379',
});

const bus = createBus({
transport,
store,
sagas: [{ definition: orderSaga }],
});

await bus.start();

Configuration​

OptionTypeDefaultDescription
urlstring-Redis connection URL
hoststring'localhost'Redis host
portnumber6379Redis port
passwordstring-Redis password
dbnumber0Database number
keyPrefixstring'saga:'Key prefix
ttlnumber-TTL in seconds
clientRedis-Existing ioredis client

Full Configuration Example​

import { RedisSagaStore } from '@saga-bus/store-redis';
import Redis from 'ioredis';

// Option 1: URL
const store = new RedisSagaStore({
url: 'redis://:password@localhost:6379/0',
});

// Option 2: Individual settings
const store = new RedisSagaStore({
host: 'localhost',
port: 6379,
password: process.env.REDIS_PASSWORD,
db: 0,
keyPrefix: 'myapp:saga:',
ttl: 86400 * 30, // 30 days
});

// Option 3: Existing client
const redis = new Redis({
host: 'localhost',
port: 6379,
maxRetriesPerRequest: 3,
retryStrategy: (times) => Math.min(times * 50, 2000),
});

const store = new RedisSagaStore({
client: redis,
keyPrefix: 'saga:',
});

// Option 4: TLS
const store = new RedisSagaStore({
host: 'redis.example.com',
port: 6380,
tls: {
rejectUnauthorized: true,
},
});

Key Structure​

{keyPrefix}{sagaName}:{sagaId}           -> Saga state (Hash)
{keyPrefix}{sagaName}:correlation:{id} -> Saga ID lookup (String)
{keyPrefix}{sagaName}:index:completed -> Completed sagas (Set)

Example keys:

  • saga:OrderSaga:abc-123 - Saga state
  • saga:OrderSaga:correlation:order-456 - Correlation lookup
  • saga:OrderSaga:index:completed - Completed index

Redis Cluster​

For cluster deployments:

import Redis from 'ioredis';

const cluster = new Redis.Cluster([
{ host: 'node1', port: 6379 },
{ host: 'node2', port: 6379 },
{ host: 'node3', port: 6379 },
]);

const store = new RedisSagaStore({
client: cluster,
keyPrefix: 'saga:',
});

Redis Sentinel​

For high availability:

import Redis from 'ioredis';

const redis = new Redis({
sentinels: [
{ host: 'sentinel1', port: 26379 },
{ host: 'sentinel2', port: 26379 },
{ host: 'sentinel3', port: 26379 },
],
name: 'mymaster',
});

const store = new RedisSagaStore({
client: redis,
keyPrefix: 'saga:',
});

TTL Configuration​

Auto-expire saga data:

// All sagas expire after 30 days
const store = new RedisSagaStore({
url: 'redis://localhost:6379',
ttl: 86400 * 30, // 30 days in seconds
});

// Different TTL for completed sagas
const store = new RedisSagaStore({
url: 'redis://localhost:6379',
ttl: 86400 * 90, // Active: 90 days
completedTtl: 86400 * 7, // Completed: 7 days
});

Docker Setup​

# docker-compose.yml
services:
redis:
image: redis:7-alpine
ports:
- "6379:6379"
command: redis-server --appendonly yes
volumes:
- redis_data:/data

volumes:
redis_data:

Optimistic Concurrency​

Uses WATCH/MULTI/EXEC for atomic updates:

// Built-in optimistic locking via Redis transactions
// Retries automatically on WATCH failure

Best Practices​

Use Appropriate TTL​

// Balance between data retention and memory usage
const store = new RedisSagaStore({
url: 'redis://localhost:6379',
ttl: 86400 * 30, // 30 days reasonable default
});

Enable Persistence​

# redis.conf
appendonly yes
appendfsync everysec

Configure Max Memory​

# redis.conf
maxmemory 1gb
maxmemory-policy volatile-lru

Use Key Prefixes​

// Namespace your keys
const store = new RedisSagaStore({
url: 'redis://localhost:6379',
keyPrefix: 'myapp:prod:saga:',
});

Monitoring​

# Check memory usage
redis-cli INFO memory

# Find saga keys
redis-cli KEYS "saga:*"

# Monitor commands
redis-cli MONITOR

See Also​