Make Cache Fetch Thread-Safe and Single-Flight

Quick Overview

Design a thread-safe cache fetch operation that coalesces concurrent misses for the same key while allowing different keys to load in parallel. Define linearization points, generation-aware publication, lock scope, timeout and error handling, deletion races, and stale completion cleanup.

Make Cache Fetch Thread-Safe and Single-Flight

Company: Tubitv

Role: Software Engineer

Category: Software Engineering Fundamentals

Difficulty: medium

Interview Round: Technical Screen

# Make Cache Fetch Thread-Safe and Single-Flight A TTL cache adds fetch(key, loader, ttl): return a valid cached value immediately; otherwise call the loader, cache a successful result, and return it. Loader errors must not be cached. Explain how to make this operation safe and efficient when many threads request the same key. ### Constraints & Assumptions - The loader can take 100 milliseconds or longer and may fail or time out. - Different keys should usually load concurrently. - The cache supports put, get, delete, and fetch. - A key can be replaced or deleted while a load is in flight. - Practice assumption: values are immutable once published. ### Clarifying Questions to Ask - Should concurrent callers share the same loader result and error? - Does delete invalidate an in-flight fetch? - Are loaders cancelable, and is stale-on-error allowed? - Is the cache in one process or distributed across processes? ### Part 1: Thread-Safe Core State Define synchronization for the value map, TTL metadata, and any recency or cleanup structures. Explain the linearization point of each operation. #### Hints - Correctness involves coordinated structures, not only a thread-safe dictionary. #### What This Part Should Cover - Atomic state transitions - Bounded lock scope - Expiration and replacement races ### Part 2: Fetch and Key Conflicts Prevent a miss storm for one key while preserving concurrency across keys. Handle loader success, error, timeout, delete, and replacement. #### Hints - The thread performing slow I/O should not hold the global cache lock. - Consider how a waiter identifies the exact generation it joined. #### What This Part Should Cover - Per-key request coalescing - Generation-aware publication - Explicit error and cancellation semantics ### What a Strong Answer Covers - A clear concurrency contract and linearization points - Fine-grained or sharded synchronization - Single-flight loading without global-lock I/O - Correct handling of stale completions, errors, and cleanup ### Follow-up Questions - How would you extend single-flight across a service fleet? - Should a transient loader error be negatively cached? - How do you prevent unbounded per-key lock objects? - What changes if values can be mutated by callers?

Quick Answer: Design a thread-safe cache fetch operation that coalesces concurrent misses for the same key while allowing different keys to load in parallel. Define linearization points, generation-aware publication, lock scope, timeout and error handling, deletion races, and stale completion cleanup.

|Home/Software Engineering Fundamentals/Tubitv
Tubitv logo
Tubitv
Feb 16, 2026, 12:00 AM
mediumSoftware EngineerTechnical ScreenSoftware Engineering Fundamentals
0
0

Make Cache Fetch Thread-Safe and Single-Flight

A TTL cache adds fetch(key, loader, ttl): return a valid cached value immediately; otherwise call the loader, cache a successful result, and return it. Loader errors must not be cached. Explain how to make this operation safe and efficient when many threads request the same key.

Constraints & Assumptions

  • The loader can take 100 milliseconds or longer and may fail or time out.
  • Different keys should usually load concurrently.
  • The cache supports put, get, delete, and fetch.
  • A key can be replaced or deleted while a load is in flight.
  • Practice assumption: values are immutable once published.

Clarifying Questions to Ask Guidance

  • Should concurrent callers share the same loader result and error?
  • Does delete invalidate an in-flight fetch?
  • Are loaders cancelable, and is stale-on-error allowed?
  • Is the cache in one process or distributed across processes?

Part 1: Thread-Safe Core State

Define synchronization for the value map, TTL metadata, and any recency or cleanup structures. Explain the linearization point of each operation.

Hints

  • Correctness involves coordinated structures, not only a thread-safe dictionary.

What This Part Should Cover Guidance

  • Atomic state transitions
  • Bounded lock scope
  • Expiration and replacement races

Part 2: Fetch and Key Conflicts

Prevent a miss storm for one key while preserving concurrency across keys. Handle loader success, error, timeout, delete, and replacement.

Hints

  • The thread performing slow I/O should not hold the global cache lock.
  • Consider how a waiter identifies the exact generation it joined.

What This Part Should Cover Guidance

  • Per-key request coalescing
  • Generation-aware publication
  • Explicit error and cancellation semantics

What a Strong Answer Covers Guidance

  • A clear concurrency contract and linearization points
  • Fine-grained or sharded synchronization
  • Single-flight loading without global-lock I/O
  • Correct handling of stale completions, errors, and cleanup

Follow-up Questions Guidance

  • How would you extend single-flight across a service fleet?
  • Should a transient loader error be negatively cached?
  • How do you prevent unbounded per-key lock objects?
  • What changes if values can be mutated by callers?
Loading comments...