Design Message Retention

Medium60 min
1 / 30
understanding8 min read

Section 1: Understanding for Message Retention

How Section 1: Understanding for Message Retention (understanding) informs Message Retention architecture and interviewer depth.

Section 1: Understanding

Message retention is primarily a deterministic policy system with storage lifecycle enforcement.

Design it as control plane plus data plane: policy authoring and precedence on one side,

expiration, tombstoning, archive export, and purge orchestration on the other.

Core invariants

  • Legal hold always overrides TTL.
  • Lifecycle actions are idempotent and replay-safe.
  • Every retention action emits immutable audit evidence.
  • Search index visibility must track message lifecycle exactly.
  • Policy changes are versioned and replayable.

Practical implementation

Store immutable message payload plus mutable lifecycle metadata: retention class, expireAt, holdState, and purgeState. A policy compiler turns human-readable rules into executable matchers with version hash.

javaOne Dark Pro
1public record RetentionDecision(String policyId, long expireAtEpochMs, boolean legalHold) {}
2public class RetentionEngine {
3 public RetentionDecision decide(MessageEnvelope m, PolicySnapshot policy) {
4 if (m.legalHold()) return new RetentionDecision(policy.id(), Long.MAX_VALUE, true);
5 long ttlMs = policy.ttlMsFor(m.channelType(), m.classification());
6 return new RetentionDecision(policy.id(), m.createdAtEpochMs() + ttlMs, false);
7 }
8}
pythonOne Dark Pro
1from dataclasses import dataclass
2
3@dataclass
4class RetentionDecision:
5 policy_id: str
6 expire_at_ms: int
7 legal_hold: bool
8
9def decide_retention(message: dict, policy: dict) -> RetentionDecision:
10 if message.get('legal_hold', False):
11 return RetentionDecision(policy['id'], 2**63 - 1, True)
12 ttl_ms = policy['ttl_ms_by_class'][message['classification']]
13 return RetentionDecision(policy['id'], message['created_at_ms'] + ttl_ms, False)
typescriptOne Dark Pro
1interface RetentionDecision { policyId: string; expireAtMs: number; legalHold: boolean }
2export function decideRetention(msg: any, policy: any): RetentionDecision {
3 if (msg.legalHold) return { policyId: policy.id, expireAtMs: Number.MAX_SAFE_INTEGER, legalHold: true };
4 const ttlMs = policy.ttlMsByClass[msg.classification] as number;
5 return { policyId: policy.id, expireAtMs: msg.createdAtMs + ttlMs, legalHold: false };
6}

Interview framing

State trade-offs clearly: hard delete is simpler conceptually but operationally risky at scale, while mark-and-sweep is safer for retries, canary rollout, and compliance auditing.

Why interviewers care

Message Retention interviews reward crisp scope, explicit trade-offs, and failure stories—not generic microservice diagrams.

The failure that defines the design

The outage to narrate is deleting data that was under legal hold. A retention policy says delete-after-ninety-days, a bulk sweep runs, and it purges messages that an active litigation hold required you to preserve — spoliation, the cardinal compliance failure, with legal and regulatory consequences far worse than keeping data too long. The fix is the spine of the design: a retention policy engine that resolves each message's effective rule from the applicable policies, with one inviolable precedence — a legal hold always wins and suppresses deletion, no matter what any delete-after rule says — and a sweep that checks the hold before purging anything. State legal-hold-suppresses-deletion-and-is-checked-first up front, because retention is a governance problem where the catastrophic error is not over-retaining but destroying something you were ordered to keep.

Key Highlights

  • Deterministic policy semantics
  • Idempotent purge and archive flow
  • Interview-ready reliability and compliance trade-offs
Interviewer signal
Tie policy choice to operational and compliance consequence.
Trade-off lens
Faster deletion can increase blast radius without replay controls.

Section Rescue Kit

Buzzwords to use:

Retention Index 1Legal Hold Override 1

Safe statements:

  • "I would lock policy precedence before tuning purge throughput."
  • "If compliance scope shifts, I can adapt by separating hold from TTL evaluation."
Design Message Retention - System Design | WinJob | WinJob