mcpField
C
caching-strategist

caching-strategist

github.com/patricio0312revDevelopment63266 installsUpdated 41w ago
Repository

About caching-strategist

A caching strategy design skill for software developers. It covers cache layers, keys, TTLs, invalidation, warming, and correctness checks.

Key features

  1. 01Plan CDN, application, database, and client caches
  2. 02Design hierarchical cache keys and TTLs
  3. 03Implement cache-aside and invalidation flows
  4. 04Warm caches and prevent stampedes
  5. 05Check fallback, monitoring, and correctness

Use cases

  1. 01Choose TTLs for data with different update rates
  2. 02Define cache invalidation on writes
  3. 03Reduce repeated loading of popular queries
  4. 04Review fallback and monitoring for cache failures

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/patricio0312rev/skills --skill caching-strategist

After installing, type/caching-strategistin Claude Code to confirm it loaded.

Details

From the project README

Caching Strategist

Design effective caching strategies for performance and consistency.

Cache Layers

CDN: Static assets, public pages (TTL: days/weeks) Application Cache (Redis): API responses, sessions (TTL: minutes/hours) Database Cache: Query results (TTL: seconds/minutes) Client Cache: Browser/app local cache

Cache Key Strategy

// Hierarchical key structure
const CACHE_KEYS = {
  user: (id: string) => `user:${id}`,
  userPosts: (userId: string, page: number) => `user:${userId}:posts:${page}`,
  post: (id: string) => `post:${id}`,
  postComments: (postId: string) => `post:${postId}:comments`,
};

// Include version in keys for easy invalidation
const CACHE_VERSION = "v1";
const key = `${CACHE_VERSION}:${CACHE_KEYS.user(userId)}`;

TTL Strategy

const TTL = {
  // Frequently changing
  REALTIME: 10, // 10 seconds
  SHORT: 60, // 1 minute

  // Moderate updates
  MEDIUM: 300, // 5 minutes
  STANDARD: 3600, // 1 hour

  // Rarely changing
  LONG: 86400, // 1 day
  VERY_LONG: 604800, // 1 week
};

// Usage
await redis.setex(key, TTL.MEDIUM, JSON.stringify(data));

Cache-Aside Pattern

export const getCachedUser = async (userId: string): Promise<User> => {
  const key = CACHE_KEYS.user(userId);

  // Try cache first
  const cached = await redis.get(key);
  if (cached) {
    return JSON.parse(cached);
  }

  // Cache miss - fetch from DB
  const user = await db.users.findById(userId);

  // Store in cache
  await redis.setex(key, TTL.STANDARD, JSON.stringify(user));

  return user;
};

Cache Invalidation

// Invalidate on update
export const updateUser = async (userId: string, data: UpdateUserDto) => {
  const user = await db.users.update(userId, data);

  // Invalidate cache
  await redis.del(CACHE_KEYS.user(userId));

  // Invalidate related caches
  await redis.del(CACHE_KEYS.userPosts(userId, "*"));

  return user;
};

// Tag-based invalidation
const addCacheTags = (key: string, tags: string[]) => {
  tags.forEach((tag) => {
    redis.sadd(`cache_tag:${tag}`, key);
  });
};

const invalidateByTag = async (tag: string) => {
  const keys = await redis.smembers(`cache_tag:${tag}`);
  if (keys.length) {
    await redis.del(...keys);
    await redis.del(`cache_tag:${tag}`);
  }
};

Cache Warming

// Pre-populate cache for common queries
export const warmCache = async () => {
  const popularPosts = await db.posts.findPopular(100);

  for (const post of popularPosts) {
    const key = CACHE_KEYS.post(post.id);
    await redis.setex(key, TTL.LONG, JSON.stringify(post));
  }
};

// Schedule warming
cron.schedule("0 */6 * * *", warmCache); // Every 6 hours

Cache Stampede Prevention

// Use locks to prevent multiple simultaneous fetches
export const getCachedWithLock = async (
  key: string,
  fetchFn: () => Promise<any>
) => {
  const cached = await redis.get(key);
  if (cached) return JSON.parse(cached);

  const lockKey = `lock:${key}`;
  const acquired = await redis.set(lockKey, "1", "EX", 10, "NX");

  if (acquired) {
    try {
      // Fetch and cache
      const data = await fetchFn();
      await redis.setex(key, TTL.STANDARD, JSON.stringify(data));
      return data;
    } finally {
      await redis.del(lockKey);
    }
  } else {
    // Wait for other request to finish
    await new Promise((resolve) => setTimeout(resolve, 100));
    return getCachedWithLock(key, fetchFn);
  }
};

Cache Correctness Checklist

- [ ] Cache keys are unique and predictable
- [ ] TTL is appropriate for data freshness
- [ ] Invalidation happens on all updates
- [ ] Related caches invalidated together
- [ ] Cache stampede prevention in place
- [ ] Fallback to DB if cache fails
- [ ] Monitoring cache hit rate
- [ ] Cache size doesn't grow unbounded
- [ ] Sensitive data not cached or encrypted
- [ ] Cache warming for critical paths

Best Practices

  • Cache immutable data aggressively
  • Short TTLs for frequently changing data
  • Invalidate on write, not on read
  • Monitor hit rates and adjust
  • Use tags for bulk invalidation
  • Prevent cache stampedes
  • Graceful degradation if cache down

Output Checklist

  • Cache key naming strategy
  • TTL values per data type
  • Invalidation triggers documented
  • Cache-aside implementation
  • Stampede prevention
  • Cache warming strategy
  • Monitoring/metrics setup
  • Correctness checklist completed

Comments

Markdown supported