Cache design
How OpenQuok uses Redis and Postgres — source of truth, cache strategy, and connection limits.
Connect your agent today
Draft from chat, review in your calendar, and publish only what you approve.
Overview
OpenQuok stores product data in Supabase (Postgres). Redis is a shared helper for cache, OAuth state, and job queues. Redis is not the source of truth for posts, users, or billing.
Configure Redis connection variables on Redis cache. Use Redis & queues for BullMQ keys and redis-cli checks.
Source of truth
| Data | Source of truth |
|---|---|
| Posts, schedules, integrations, users, orgs, billing | Postgres |
| API read cache (profiles, RBAC, calendar lists, blog, listings) | Postgres (copy in Redis) |
| OAuth PKCE state | Redis (short TTL; not a DB copy) |
| BullMQ jobs and Flowcraft run state | Redis (pipeline only; schedule rows stay in Postgres) |
Write scheduled posts to Postgres before you enqueue a worker job. If Redis loses a job, reconciliation can rescan Postgres. Do not treat the queue as the schedule record.
Three Redis roles
One Redis host can serve all roles. The API and workers use two clients:
| Role | Client | Key examples |
|---|---|---|
| Application cache | redis package (RedisCacheProvider) | REDIS_PREFIX (default app:cache:) |
| Queues and workflow | ioredis / BullMQ | bull:<queue>:*, workflow:state |
| OAuth connect | Same cache client | login:, organization:, … under the cache prefix |
Optional REDIS_BULLMQ_DB puts queue keys on a separate logical DB. Cache keys use REDIS_DB.
Cache strategy
Reads — read-aside. Services call getOrSet: read Redis; on miss, load Postgres, then set Redis with TTL. Code: backend/connections/cache/CacheService.ts.
Writes — write-around. Mutations write Postgres first. Then CacheInvalidationService deletes keys or patterns (for example calendar list caches after a post change). OpenQuok does not write-through every read cache on each DB update.
TTL — backstop. Default CACHE_DEFAULT_TTL is 900 seconds. OAuth state TTL is 3600 seconds. Stale data can exist until invalidation or TTL expiry.
Production must use CACHE_PROVIDER=redis (or Redis env with auto-force in production) so OAuth state works across Vercel instances.
Connection limits
Managed Redis plans cap concurrent connections (for example 256 on Redis Cloud Essentials 250 MB).
| Component | Typical connections |
|---|---|
| Each warm Vercel API instance | 1 cache client + short-lived queue clients on enqueue |
| Each Railway worker | 1–2 persistent ioredis clients (BullMQ) + optional cache client |
| Health probes | Can open extra clients if each probe creates a new connection |
Traffic spikes can raise connection count fast. Redis does not remove idle clients for you. Stale TCP sessions can stay until the client disconnects or you run CLIENT KILL.
Production
Watch Connected clients in your Redis provider dashboard. Keep BULL_BOARD_ENABLED off on serverless API unless you need the dashboard there. Prefer one worker replica per queue service.
Check connections
redis-cli -u 'redis://default:PASSWORD@HOST:PORT' --tls INFO clients | grep connected_clients
redis-cli -u 'redis://...' --tls CLIENT LIST Kill only clients with idle over one day and no recent bzpopmin / setex activity. Do not kill live worker or API rows.