Redis Integration & Caching
Relevant source files
The following files were used as context for generating this wiki page:
The Redis integration within the Subito project serves as a high-performance data layer used primarily for application-level caching and request rate limiting. By leveraging an in-memory data store, the system reduces latency for frequently accessed data and protects API resources from excessive traffic or brute-force attempts.
The integration is centered in the @subito/api service, utilizing the ioredis library for connection management and bullmq for potential queueing operations. It provides a standardized interface for basic CRUD operations on cached data and advanced Lua-based atomic operations for security middleware.
Sources: apps/api/package.json:28-35, apps/api/src/lib/redis.ts:1-10
Core Connection & Configuration
The Redis client is instantiated using the REDIS_URL environment variable, defaulting to a local instance if not provided. The configuration includes a custom retry strategy and lifecycle event logging to ensure system observability.
Connection Parameters
| Parameter | Description | Source |
|---|---|---|
maxRetriesPerRequest | Set to null to ensure compatibility with worker libraries like BullMQ. | apps/api/src/lib/redis.ts:8 |
enableReadyCheck | Disabled to allow immediate command execution upon connection. | apps/api/src/lib/redis.ts:9 |
retryStrategy | Linear delay starting at 50ms, capped at 2000ms. | apps/api/src/lib/redis.ts:10-13 |
The connection status is tracked via standard Redis events:
- connect: Logs a success message when the client establishes a connection.
- error: Logs connection failures through the application logger.
Sources: apps/api/src/lib/redis.ts:16-22
Caching Operations
The project implements a set of wrapper functions to simplify JSON serialization and TTL (Time-To-Live) management. These utilities provide a consistent interface for the rest of the application.
Key Functions
cacheGet<T>(key): Retrieves a value and parses it from JSON into the specified type.cacheSet(key, value, ttlSeconds): Serializes a value and stores it with an expiration time. Defaults to 24 hours (86,400 seconds) if no TTL is provided.cacheDel(key): Removes a specific key from the store.cacheDelPattern(pattern): A non-blocking deletion method that usesSCANin chunks of 100 to find and remove keys matching a pattern, avoiding the performance penalties of theKEYScommand.
Sources: apps/api/src/lib/redis.ts:24-60
Caching Flow
The following diagram illustrates the standard data retrieval flow using the caching layer.
The diagram shows how the system prioritizes Redis lookups before falling back to the primary database.
Sources: apps/api/src/lib/redis.ts:24-43
Rate Limiting Middleware
A critical use case for Redis in this project is the rateLimit middleware. It uses atomic Redis operations to track request counts per user or IP address within a sliding time window.
Atomic Lua Scripting
To prevent race conditions (TOCTOU - Time-of-check to time-of-use), the system utilizes a Lua script executed via redis.eval. This script performs the increment and expiration logic in a single atomic operation.
const RATE_LIMIT_SCRIPT = `
local key = KEYS[1]
local window = tonumber(ARGV[1])
local current = redis.call('INCR', key)
if current == 1 then
redis.call('EXPIRE', key, window)
end
local ttl = redis.call('TTL', key)
return {current, ttl}
`
Sources: apps/api/src/middleware/rate-limit.ts:13-22
Predefined Rate Limiters
The application defines specific limits for different functional areas:
| Limiter | Window | Max Requests | Key Prefix |
|---|---|---|---|
authRateLimit | 60s | 10 | ratelimit:auth |
apiRateLimit | 60s | 100 | ratelimit:api |
checkoutRateLimit | 60s | 5 | ratelimit:checkout |
Sources: apps/api/src/middleware/rate-limit.ts:68-84
Rate Limiting Sequence
This sequence diagram shows the interaction between the client, Hono middleware, and Redis during a rate-limited request.
The diagram depicts the logic for evaluating request eligibility based on Redis data.
Sources: apps/api/src/middleware/rate-limit.ts:25-66
Environment Integration
Redis is integrated into the broader monorepo infrastructure. It is defined as a global environment dependency in turbo.json, ensuring that tasks are re-run if the Redis configuration changes.
- Global Variable:
REDIS_URL - Related Packages:
@subito/apidepends onioredisandbullmqfor Redis-backed functionality.
Sources: turbo.json:11, apps/api/package.json:30-34
Persistence Comparison
While Redis handles transient data and rate limits, the project uses PostgreSQL for persistent relational data. The database schema includes a refresh_tokens table which, while similar in purpose to session storage, is maintained in the primary database for long-term persistence across sessions.
Sources: packages/db/drizzle/0000_normal_the_order.sql:22-30