codingstuff.io
ExploreTutorialsProblemsCS Subjects
Get Started
ExploreTutorialsProblemsCS Subjects
Get Started
codingstuff.io

Master the art of building software through interactive tutorials, real-world problems, and guided projects.

Pune, Maharashtra, India

codingstuffmail@gmail.com

Product

  • Explore
  • Tutorials
  • Problems
  • CS Subjects

Company

  • About
  • Contact
  • Privacy Policy
  • Terms & Conditions
  • Sitemap

© 2026 codingstuff.io. All rights reserved.

Built with ❤️ for developers everywhere

/
/
All Tutorials
🏗️

System Design

10 / 49 topics
8Caching Strategies9Types of Caches10Cache Invalidation
Tutorials/System Design/Cache Invalidation
🏗️System Design

Cache Invalidation

Updated 2026-05-15
10 min read

Cache Invalidation

Introduction

Caching is a fundamental technique used in software systems to improve performance by temporarily storing frequently accessed data. However, maintaining the consistency between the cache and the underlying data source can be challenging, especially when updates occur. This tutorial will explore various techniques for cache invalidation, ensuring that your cached data remains up-to-date.

Concept

Cache invalidation refers to the process of removing or updating entries in a cache so that they reflect the current state of the underlying data source. There are several strategies to handle cache invalidation:

  1. Time-Based Expiration: Set an expiration time for each cache entry, after which it is automatically invalidated.
  2. Event-Driven Invalidation: Invalidate cache entries based on specific events or changes in the data source.
  3. Cache Stampede Prevention: Use techniques like locking to prevent multiple threads from simultaneously regenerating the same data.

Examples

Time-Based Expiration

Time-based expiration is one of the simplest and most common strategies for cache invalidation. Each entry in the cache has a timestamp, and if the current time exceeds this timestamp, the entry is considered stale and should be invalidated.

Example Code

class Cache {
  constructor() {
    this.store = {};
  }

  set(key, value, ttl) { // ttl in milliseconds
    const expiryTime = Date.now() + ttl;
    this.store[key] = { value, expiryTime };
  }

  get(key) {
    const entry = this.store[key];
    if (!entry || entry.expiryTime < Date.now()) {
      return null; // Cache miss or expired
    }
    return entry.value;
  }
}

// Usage
const cache = new Cache();
cache.set('user:1', { name: 'Alice' }, 5000); // Set with a TTL of 5 seconds

console.log(cache.get('user:1')); // Output: { name: 'Alice' }
setTimeout(() => {
  console.log(cache.get('user:1')); // Output: null (expired)
}, 6000);

Event-Driven Invalidation

Event-driven invalidation involves listening for specific events that indicate changes in the data source and then invalidating the relevant cache entries. This approach ensures that the cache is always consistent with the underlying data.

Example Code

class Cache {
  constructor() {
    this.store = {};
  }

  set(key, value) {
    this.store[key] = value;
  }

  get(key) {
    return this.store[key];
  }

  invalidate(key) {
    delete this.store[key];
  }
}

const cache = new Cache();
cache.set('user:1', { name: 'Alice' });

// Simulate a data change event
function onDataChange(key) {
  console.log(`Invalidating cache for key: ${key}`);
  cache.invalidate(key);
}

onDataChange('user:1');
console.log(cache.get('user:1')); // Output: null (invalidated)

Cache Stampede Prevention

Cache stampedes occur when multiple requests simultaneously try to regenerate the same data after a cache entry expires. To prevent this, you can use locking mechanisms such as mutexes.

Example Code

class Cache {
  constructor() {
    this.store = {};
    this.locks = new Set();
  }

  async getWithLock(key, fetchData) {
    if (this.locks.has(key)) {
      await new Promise(resolve => setTimeout(resolve, 100)); // Wait and retry
      return this.getWithLock(key, fetchData);
    }
    this.locks.add(key);

    try {
      const value = this.store[key];
      if (!value) {
        const newValue = await fetchData();
        this.store[key] = newValue;
        return newValue;
      }
      return value;
    } finally {
      this.locks.delete(key);
    }
  }
}

const cache = new Cache();

async function fetchData() {
  console.log('Fetching data...');
  return { name: 'Alice' };
}

cache.getWithLock('user:1', fetchData).then(data => {
  console.log(data); // Output: { name: 'Alice' }
});

What's Next?

In this section, we explored various techniques for cache invalidation, including time-based expiration, event-driven invalidation, and cache stampede prevention. Understanding these strategies is crucial for building efficient and reliable caching systems.

Next, you might want to dive deeper into database design, which plays a critical role in managing data consistency and performance. Learning how to design databases effectively will help you build robust applications that can handle large volumes of data efficiently.

Happy coding!


PreviousTypes of CachesNext Database Design

Recommended Gear

Types of CachesDatabase Design