Feature Flag Service Tutorial · Module 06 of 10

Caching & Performance

Cache flag definitions in Redis for fast evaluation. Implement cache invalidation on flag updates. Add metrics for cache hit rates, evaluation latency, and database load. Support distributed caching across multiple instances. By the end, the service can handle 10K+ evaluations/sec.

~4–5 hrsIntermediatePerformance focus
← Back to Module 06 overview
What You'll Have at the End

Definition of Done

  • Redis caching: Flags cached with 5-minute TTL.
  • Cache invalidation: Flag updates invalidate Redis cache immediately.
  • Metrics: Cache hit rate (should be > 99%), evaluation latency (p95 < 50ms).
  • Distributed cache: Multiple app instances share Redis cache.
  • Fallback: If Redis unavailable, fall back to database.
  • Load test: 10K evaluations/sec with 100% cache hit rate.
  • Database queries reduced by 99% with caching.
The Steps

Build It

STEP 1

Add Redis caching to flag storage

Create src/cache/flagCache.ts:

import { Redis } from 'ioredis';

export class FlagCache {
  private redis: Redis;
  private ttl: number = 300; // 5 minutes

  constructor(redisUrl: string) {
    this.redis = new Redis(redisUrl);
  }

  async getFlagWithRules(flagId: string) {
    const cacheKey = `flag:${flagId}`;
    const cached = await this.redis.get(cacheKey);
    if (cached) return JSON.parse(cached);
    return null;
  }

  async setFlagWithRules(flagId: string, flag: any) {
    const cacheKey = `flag:${flagId}`;
    await this.redis.setex(cacheKey, this.ttl, JSON.stringify(flag));
  }

  async invalidateFlag(flagId: string) {
    await this.redis.del(`flag:${flagId}`);
  }

  async invalidateAllFlags() {
    const keys = await this.redis.keys('flag:*');
    if (keys.length > 0) {
      await this.redis.del(...keys);
    }
  }

  async getMetrics() {
    const info = await this.redis.info('stats');
    const dbSize = await this.redis.dbsize();
    return { info, dbSize };
  }
}