Chapters of From Frontend to Full-Stack Backend

Week 3 - Interview-এ সবচেয়ে বেশি জিজ্ঞেস করা TopicsChapter 15 of 283 min read

Caching - Redis, the cache-aside pattern and the hard invalidation question

Why caches are needed, the cache-aside pattern, TTL, when to invalidate, stale data risks

Your menu page is viewed a thousand times a day, but the menu changes once a week. Yet every single view fires the same query at the database and brings the same data. It is a bit like this - looking up the same address by opening the notebook again and again, when saving the address in your phone would have done it. A cache is that saved arrangement: keeping frequently needed data in a fast place (Redis - it lives in memory), so you do not have to go to the database every time.

The cache-aside pattern - the most used shape

async function getMenu() {
  const cached = await redis.get("menu:all");
  if (cached) return JSON.parse(cached);   // cache hit

  const menu = await db.menu.findMany();   // cache miss - from the database
  await redis.set("menu:all", JSON.stringify(menu), "EX", 300); // 5 minute TTL
  return menu;
}

The shape is simple: first look in the cache, and if you find it, return it at once. If not, bring it from the database and keep it in the cache, so the next person gets it. EX 300 is the TTL - after 5 minutes the cache deletes itself, and the next request brings fresh data.

Invalidation - the cache's real hard problem

The cache's most complex question is: when the data changes, when do you remove the old cache? The admin changed a price on the menu, but the old price stayed in the cache - the customer will see the wrong price. There are two weapons: TTL (expiring on its own - for places where seeing slightly old data sometimes is acceptable), and active invalidation - deleting the related cache key the moment the data changes.

// The moment a price changes, drop the menu cache
async function updateMenuItem(id, data) {
  const item = await db.menu.update({ where: { id }, data });
  await redis.del("menu:all");
  return item;
}

What to cache is also a matter of judgement: things that are read often but change rarely (menu, settings, popular products) - those. Things that are different every time or must always be exactly right (bank balance, the final state of stock) - be careful there, or do not cache at all.

The mistake everyone makes

Caching without arranging TTL or invalidation - then old data keeps circulating forever. The opposite is also a mistake: caching everything. The more the cache grows, the more the stale-data risk grows. Cache only where the benefit is clear.

Today's practice

Put Redis in your API and add the cache-aside pattern to a menu or product list endpoint. Then send two requests and measure the time - the first time from the database, the second time from the cache. Finally, update an item and check whether invalidation is working.

How to say it in an interview

I use the cache-aside pattern - I look in Redis first, and if I do not find it I bring it from the database and keep it with a TTL. For invalidation, where changed data must show at once, I delete the key at update time; where slightly old data is fine, TTL alone is enough.

All chapters of From Frontend to Full-Stack Backend