When designing and implementing web interfaces to ensure they are usable by everyone.
The English summary is being prepared. Showing the original description.
When improving read performance and reducing database load.
The English summary is being prepared. Showing the original description.
Review the instructions the agent will receive before you install.
Databases are slow; caches are fast. This skill teaches teams to strategically cache frequently accessed data in fast storage (Redis, Memcached) to intercept requests before they hit the database, dramatically reducing latency and database load. Caching is NOT a substitute for proper database optimization.
❌ Anti-pattern (No fallback, infinite TTL, no invalidation):
// WRONG: No fallback if cache fails
const getUser = async (userId) => {
return redis.get(`user:${userId}`); // Fails if Redis is down
};
// WRONG: Infinite TTL
redis.set(`config:app-settings`, settings); // Never expires = stale data forever
// WRONG: No invalidation on update
async function updateUser(userId, data) {
await db.users.update(userId, data);
// Forgot to clear cache - stale data served
}
// WRONG: Cache stampede - all requests hit DB when key expires
const getExpensiveData = async () => {
const cached = await redis.get('expensive-data');
if (!cached) {
// All concurrent requests hit this - DB spike
const data = await slowQuery();
await redis.set('expensive-data', data, { ex: 3600 });
return data;
}
return cached;
};
✅ Correct pattern (Fallback, TTL, invalidation, stampede prevention):
// CORRECT: Fallback to database on cache miss or failure
const getUser = async (userId) => {
try {
const cached = await redis.get(`user:${userId}`);
if (cached) return JSON.parse(cached);
} catch (e) {
logger.warn('Cache miss, falling back to DB', e);
}
// Fallback to DB
const user = await db.users.findById(userId);
// Repopulate cache
try {
await redis.setex(`user:${userId}`, 3600, JSON.stringify(user)); // 1 hour TTL
} catch (e) {
logger.warn('Failed to cache, but returning DB data', e);
}
return user;
};
// CORRECT: TTL on all cache entries
redis.setex('config:app-settings', 86400, JSON.stringify(settings)); // 24 hour TTL
// CORRECT: Invalidate cache on mutations
async function updateUser(userId, data) {
await db.users.update(userId, data);
await redis.del(`user:${userId}`); // Clear specific key
}
// CORRECT: Prevent cache stampede with locks
const stampedeLock = new Mutex();
const getExpensiveData = async () => {
const cached = await redis.get('expensive-data');
if (cached) return JSON.parse(cached);
// Use lock to ensure only one request fetches from DB
return stampedeLock.runExclusive(async () => {
// Double-check if another request already populated cache
const cached = await redis.get('expensive-data');
if (cached) return JSON.parse(cached);
const data = await slowQuery();
await redis.setex('expensive-data', 3600, JSON.stringify(data));
return data;
});
};
No reviews yet. Tell others what you thought.
No login needed. Share how it worked for you, ask a question, or note where it did not run.
No comments yet. Be the first to write one.
When designing and implementing web interfaces to ensure they are usable by everyone.
The English summary is being prepared. Showing the original description.
When creating or extending an HTTP API for client consumption.
The English summary is being prepared. Showing the original description.
When configuring automated build, test, and deployment workflows for a repository.
The English summary is being prepared. Showing the original description.
When asynchronously reviewing peer code before merging into the main branch.
The English summary is being prepared. Showing the original description.
When addressing slow application endpoints, high database CPU usage, or standardizing data access patterns.
The English summary is being prepared. Showing the original description.
When isolating and fixing unpredictable or complex software bugs.
The English summary is being prepared. Showing the original description.