Building a Grow-Only Counter on a Sequentially Consistent KV Store

Dev world bickers over a counter that only goes up

TLDR: Fly.io’s post shows how to build a counter that only increases, first with an atomic check‑and‑update, then nodding to a multi‑copy approach that avoids conflicts. Commenters split into “retry‑loop simplicity” vs “CRDT reliability,” roasting infinite loops and hailing designs that survive broken networks—because outages are real.

Fly.io’s latest challenge—make a counter that only goes up using a built‑in key‑value store—sent the internet into pure engineer theater. The post walks through a simple approach, then a safer fix using “compare‑and‑swap” (a one‑shot check‑and‑update), and name‑drops CRDTs, the fancy “copies don’t fight” data design. But the comments? Carnival.

One camp is screaming “just make it atomic” with compare‑and‑swap loops, cheering the tidy code that retries until it sticks. The other camp roars back that infinite retry loops turn into a hamster wheel the moment the network splits—remember, the test literally breaks the cluster apart and expects every node to end with the same total. Cue memes about Schrödinger’s Counter and servers doing cardio. Someone dropped Maelstrom links like receipts, while others waved CRDTs as the grown‑up option: let each node keep its own number and add them up later.

Drama peaked when a “keep it simple” fan called CRDTs “overkill for a counter,” prompting a wave of “production at 3 a.m. says hi” replies. Team Atomic loves the clarity; Team CRDT wants peace during chaos. In between, jokesters declared this “increment wars,” comparing the counter to gym reps, startup valuations, and coffee intake—always rising, never enough. The code is solid, but the comment section? That’s where the real test is running.

Key Points

  • The task is to implement a grow-only counter on Maelstrom’s sequentially consistent key-value service (SeqKV).
  • Maelstrom’s g-counter test runs with 3 nodes, rate 100, 20-second limit, and a partition nemesis, verifying that final reads see the full sum.
  • A naive read-modify-write approach using a single key (counter) fails under concurrency due to lost updates.
  • Two solutions are proposed: use atomic CompareAndSwap (CAS) for updates or adopt a CRDT-based design to avoid conflicting writes.
  • A CAS-based retry loop is shown to atomically add deltas, with the note that practical implementations should include timeouts.

Hottest takes

"While(true) { CAS; } is not a strategy, it’s a cry for help" — spinlock_sad
"It’s a counter that only goes up—like my stress levels" — dev_doomer
"Real adults use CRDTs; everyone else prays to a leader" — turing_tea
Made with <3 by @siedrix and @shesho from CDMX. Powered by Forge&Hive.