Telaio
Modules

Caching

Redis-backed cache with graceful degradation, stale-while-revalidate config service, and builder integration.

Caching

Telaio's cache module wraps redis (node-redis) with two important properties: it degrades silently when Redis is unavailable, and it provides a typed record API so you do not have to manually serialize/deserialize JSON.

Graceful degradation

When Redis is disabled (enabled: false) or the connection fails, every cache operation silently returns null or does nothing. The app keeps running. Caching is a performance layer -- losing it should never take down a service.

This is intentional. You do not need try/catch around cache calls.

createCache()

import { createCache } from 'telaio/cache';

// Config-style: reads REDIS_ENABLED and REDIS_URL from your loaded config
const cache = createCache(config);

// Direct options
const cache = createCache({
  enabled: true,
  url: 'redis://localhost:6379',
});
OptionTypeDefaultDescription
enabledbooleantrueSet to false to run without Redis
urlstringredis://localhost:6379Redis connection URL

Cache methods

// String cache
await cache.set('session:abc', 'userId:123', 3600); // TTL in seconds
const value = await cache.get('session:abc');        // string | null

// JSON records -- serialized automatically
await cache.setRecord('user:123', { name: 'Alice', plan: 'pro' }, 300);
const user = await cache.getRecord<User>('user:123'); // User | null

// Delete
await cache.delete('session:abc');

// Disconnect
await cache.close();
MethodDescription
get(key)Fetch a raw string value
set(key, value, ttl?)Store a raw string, optionally with a TTL in seconds
getRecord<T>(key)Fetch and JSON-parse a stored object
setRecord(key, value, ttl?)JSON-serialize and store an object
delete(key)Remove a key
close()Disconnect from Redis

All methods return null or do nothing silently when Redis is disabled or unreachable.

Raw Redis client

If you need operations not covered by the typed API (pipelines, pub/sub, Lua scripts), access the underlying node-redis client pool directly:

const cache = createCache(config);

if (cache.redis) {
  await cache.redis.zAdd('leaderboard', { score, value: userId });
  const top10 = await cache.redis.zRange('leaderboard', 0, 9, { REV: true });
}

cache.redis is null when caching is disabled, so guard before using it.

Full example

import { createCache } from 'telaio/cache';

const cache = createCache(config);

// Simple string cache
await cache.set('session:abc', 'userId:123', 3600); // 1 hour TTL
const value = await cache.get('session:abc');

// JSON records
await cache.setRecord('user:123', { name: 'Alice', plan: 'pro' }, 300);
const user = await cache.getRecord<User>('user:123');

// If Redis is down, all operations silently return null/undefined
// The app keeps running -- caching is a performance layer

Builder integration

const app = await createApp({ config })
  .withCache()               // options derived from config
  .build();

app.cache  // Cache instance

Pass a pre-created instance or explicit options:

.withCache({ instance: myCache })
.withCache({ cacheOptions: { url: 'redis://custom:6379' } })

LiveConfigService

LiveConfigService<T> provides a stale-while-revalidate (SWR) config pattern backed by both a database table and Redis. It is useful for feature flags or runtime config values that change infrequently but must be read on every request.

import { LiveConfigService } from 'telaio/cache';

const liveConfig = new LiveConfigService<AppConfig>({
  db,
  cache,
  ttl: 60,        // seconds before revalidating from DB
  key: 'app-config',
});

const config = await liveConfig.get();  // returns cached value if fresh

On a cache hit the value is returned immediately. On a miss or after TTL expiry the value is fetched from the database, written back to Redis, and returned.

On this page