Storage Configuration
Overview
OpenZeppelin Relayer supports two storage backends for persisting configuration data and transaction state. The choice of storage backend affects how configuration is managed, data persistence, and performance characteristics.
Storage type determines how your configuration changes persist and how file-based and API-based configuration interact. Choose the right storage type for your deployment needs.
Community Contributions Welcome: Additional storage backends (such as PostgreSQL, MongoDB, or other databases) are welcomed as contributions from the open source community. The storage system is designed to be extensible, making it straightforward to add new storage implementations.
Storage Types
In-Memory Storage
In-memory storage keeps all configuration and transaction data in the application’s memory.
Use Cases
- Development and testing environments
- Temporary deployments
- Single-instance deployments
- When data persistence across restarts is not required
Characteristics
- Fast Performance: No network overhead for data access
- No External Dependencies: Does not require Redis or other external services
- No Persistence: All data is lost when the container restarts
- Single Instance: Cannot be shared across multiple relayer instances
Configuration Sync Behavior
- Configuration from
config.jsonis loaded on every startup - API changes are not synchronized back to
config.jsonfile - All API-based configuration changes are lost on restart
- File-based configuration always takes precedence on startup
# Enable in-memory storage
REPOSITORY_STORAGE_TYPE=in-memoryRedis Storage
Redis storage persists all configuration and transaction data in a Redis database.
Use Cases
- Production deployments
- Multi-instance deployments
- When data persistence is required
- Scalable environments
- When API-based configuration changes should persist
Characteristics
- Persistent: Data survives container restarts
- Network Dependency: Requires Redis connection
- Encryption: Supports encryption at rest for sensitive data
Configuration Sync Behavior
- Configuration from
config.jsonis loaded into Redis only once during the first startup - Subsequent startups use the configuration stored in Redis
- API changes are persisted and survive restarts
- File-based configuration can override Redis by setting
RESET_STORAGE_ON_START=true
# Enable Redis storage
REPOSITORY_STORAGE_TYPE=redis
REDIS_URL=redis://localhost:6379
STORAGE_ENCRYPTION_KEY=your-encryption-key-hereConfiguration Reference
Core Storage Settings
| Environment Variable | Default Value | Accepted Values | Description |
|---|---|---|---|
REPOSITORY_STORAGE_TYPE | in-memory | in-memory, redis | Type of storage backend used for storing configuration and transaction data. |
RESET_STORAGE_ON_START | false | true, false | When true, clears all data from storage on startup and reloads from config files. Useful for forcing file-based configuration to override stored data. |
TRANSACTION_EXPIRATION_HOURS | 4 | number | Number of hours after which transactions in a final state are automatically removed from storage to prevent storage bloat. |
Redis-Specific Settings
| Environment Variable | Default Value | Accepted Values | Description |
|---|---|---|---|
REDIS_URL | redis://localhost:6379 | Redis connection string | Full connection URL for the Redis primary instance. Used for all write operations and read operations when REDIS_READER_URL is not set. |
REDIS_READER_URL | (none) | Redis connection string | Optional separate endpoint for read operations. When set, read operations (GET, MGET, etc.) use this endpoint while writes use REDIS_URL. Useful for AWS ElastiCache with read replicas to distribute read load. |
REDIS_READER_POOL_MAX_SIZE | 1000 | number | Optional separate pool size for reader connections. Useful for read-heavy workloads where more reader connections are beneficial. |
REDIS_CONNECTION_TIMEOUT_MS | 10000 | number (milliseconds) | Maximum time to wait when connecting to Redis before timing out. |
REDIS_POOL_MAX_SIZE | 500 | number | Maximum number of connections in the Redis connection pool. Adjust based on your Redis instance capacity, workload, and deployment scale. |
REDIS_POOL_TIMEOUT_MS | 10000 | number (milliseconds) | Maximum time to wait for a connection from the pool before timing out. Higher values help handle traffic spikes. |
REDIS_KEY_PREFIX | oz-relayer | string | Prefix added to all Redis keys. Useful for namespacing when sharing Redis with other applications. |
STORAGE_ENCRYPTION_KEY | `` | string (base64) | Encryption key used to encrypt sensitive data at rest in Redis. Generate using cargo run --example generate_encryption_key. |
Security Considerations
Redis Security
When using Redis storage in production:
- Use encryption at rest: Always set
STORAGE_ENCRYPTION_KEY - Secure Redis access: Use Redis AUTH, TLS, and network security
- Network isolation: Deploy Redis in a private network
- Regular backups: Implement Redis backup strategy
- Monitor access: Log and monitor Redis access patterns
AWS ElastiCache with Read Replicas
When using AWS ElastiCache with read replicas, you can distribute read load across multiple nodes by configuring separate endpoints:
# AWS ElastiCache configuration with read replicas
REDIS_URL=redis://my-cluster.xxx.cache.amazonaws.com:6379 # Primary endpoint (writes)
REDIS_READER_URL=redis://my-cluster-ro.xxx.cache.amazonaws.com:6379 # Reader endpoint (reads)
REDIS_POOL_MAX_SIZE=200 # Connections to primary
REDIS_READER_POOL_MAX_SIZE=500 # More connections for reads (optional)Benefits:
- Reduced primary load: Read operations are distributed to replica nodes
- Improved read performance: Multiple replicas can handle concurrent reads
- Better fault tolerance: Read availability continues even during primary failover
- Cost efficiency: Smaller primary instance with multiple read replicas
When REDIS_READER_URL is not set:
- All operations (reads and writes) use
REDIS_URL - This maintains backward compatibility with single-endpoint configurations
- Suitable for standalone Redis or when read scaling is not needed
Connection Pool Tuning
Redis connection pooling improves performance and prevents connection exhaustion. Configure pool size based on your Redis instance capacity, workload, and deployment scale.
Factors to consider:
- Redis instance capacity: Check your Redis instance's maximum connection limit (e.g., ElastiCache small instances support 65,000+ connections)
- Transaction volume: Higher TPS requires more connections
- Number of relayers: More active relayers increase concurrent operations
- Instance count: Divide total connection budget across multiple relayer instances
- Traffic patterns: Account for traffic spikes and peak loads
Configuration:
REDIS_POOL_MAX_SIZE=500 # Adjust based on instance capacity and workload
REDIS_POOL_TIMEOUT_MS=15000 # Time to wait for available connectionEncryption at Rest
Sensitive configuration data is encrypted before being stored in Redis when STORAGE_ENCRYPTION_KEY is provided.
Encrypted Data Includes:
- Signer private keys and passphrases
- Webhook signing keys
- API keys (when stored in configuration)
- Other sensitive configuration values
Generate Encryption Key:
# Generate a secure encryption key
cargo run --example generate_encryption_key
# Alternative using OpenSSL
openssl rand -base64 32Transaction Storage Management
Automatic Cleanup
Transactions are automatically removed from storage after reaching their final state to prevent storage bloat:
# Configure transaction retention (default: 4 hours)
TRANSACTION_EXPIRATION_HOURS=8Final Transaction States:
confirmed- Transaction confirmed on blockchainfailed- Transaction failed and will not be retriedcancelled- Transaction was cancelled by userexpired: - Transaction was expired