Design Message Reactions

Medium50 min
1 / 30
understanding6 min read

Message Reactions: Problem Statement and Interview Framing

How Message Reactions: Problem Statement and Interview Framing shapes architecture and interviewer follow-ups for Design Message Reactions.

Message Reactions: Problem Statement and Interview Framing

Frame reactions as lightweight social signals on immutable messages—Slack emoji rows, Discord super-reactions, Messenger tapbacks—not as a second messaging channel. In Slack and Discord, reactions are social feedback without spawning new messages—they reduce channel noise while signaling consensus, humor, or acknowledgment. Your design must keep per-user-per-emoji uniqueness, make counts converge under concurrent adds, and fan out efficiently to thousands of viewers on viral posts.

Design mechanics for section 1

Treat every reaction toggle as an append-only event with a stable idempotency key derived from (message_id, user_id, emoji, client_op_id). The command handler validates message visibility, membership in the channel, and emoji allowlists before persisting. Aggregates are a projection, not the source of truth—if Redis and Postgres disagree, replay events from the log.

For viral messages, shard counters by hash(message_id, emoji) across N Redis cells; merge at read time. Cap who-reacted list payloads to 20 user IDs plus “+1.2K”; full list loads on demand. Threaded messages inherit parent channel ACLs; reaction notifications usually target thread participants only.

Operations and SLO anchors

Target p99 add latency 250ms end-to-end in-region; aggregate visibility within 1.5s at p99 under normal load. Alert on aggregate_drift_count, reaction_fanout_lag_ms, and hot_shard_skew_ratio. During incidents, disable who-reacted expansion first, then throttle custom emoji uploads, never drop add acknowledgements silently.

Interview pivots unique to §1

If pressed on cost, cite 3.6B events/day and counter cache memory math. If pressed on Facebook/Discord “super reactions,” explain paid bursts as rate-limited weighted counters with separate billing idempotency. If asked about moderation, describe admin purge as tombstone events that subtract counts deterministically.

Section 1 synthesis

Message Reactions: Problem Statement and Interview Framing should connect back to the invariant: one membership row per (message, user, emoji), monotonic version numbers on aggregates, and batched real-time delivery. Mention how this differs from read receipts (state machine) and typing indicators (ephemeral soft state)—reactions are commutative toggles with compact summaries.

javaOne Dark Pro
1public record ReactionEvent(String messageId, String userId, String emoji, boolean added, String idempotencyKey) {}
pythonOne Dark Pro
1def reaction_dedupe_key(message_id: str, user_id: str, emoji: str) -> str:
2 return f"{message_id}:{user_id}:{emoji}"
typescriptOne Dark Pro
1export interface ReactionSummary { emoji: string; count: number; userIdsSample: string[]; }
2export function mergeReactionDelta(prev: ReactionSummary[], delta: ReactionSummary): ReactionSummary[] {
3 return prev.map((r) => (r.emoji === delta.emoji ? { ...r, count: r.count + delta.count } : r));
4}

Why interviewers care

Message Reactions 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 the hot-counter meltdown on a viral message. A celebrity post or a company-wide announcement gets millions of reactions in minutes, all incrementing the same (message, emoji) counter — and a single naive row or key becomes a write hotspot that throttles and skews latency for everyone. The fix is structural: shard the counter (sum of per-shard sub-counters), treat counts as eventually consistent (approximate is fine for a reaction tally), and dedup membership separately. A reactions system lives or dies on absorbing a flood of writes to one hot message without making the count a contended bottleneck.

Key Highlights

  • §1: Frame reactions as lightweight social signals on immutable messages—Slack emoji rows, Discord super-reactions, Messenger tapbacks—not as a second messaging channel.
  • Unique (message,user,emoji) membership drives counts
  • Event log enables replay after cache loss
  • Shard hot counters; batch WebSocket deltas
Strong signal
For §1, lead with uniqueness + event-sourced aggregates before naming vendors.
Practical tip
When counts disagree with membership, replay Kafka—not manual SQL patches.

Section Rescue Kit

Buzzwords to use:

Commutative reaction toggle-1Counter shard-1

Safe statements:

  • "I will draw the idempotent add/remove API before the database schema."
  • "I will quantify reaction amplification before choosing cache sizes."
Design Message Reactions - System Design | WinJob | WinJob