Moving the heartbeat to Go

milestone architecture, go, reliability

A management sim’s honesty lives in the clock and the queues: if ticks double-fire or match publish fans out twice, the world invents ghosts. Mid-July’s stake was to move that heartbeat into dedicated Go binaries without changing the product contract Nest had already taught us — and then to make restarts boring.

What shipped was a Go worker and scheduler speaking the same Redis job shapes Nest used, gated by explicit queue ownership so cutover could be gradual rather than a big bang. Match simulation (in-process engine by default), game-day phases, finance, transfers, training, scouting, narrative, inbox fan-out, cup draws, season lifecycle, and more landed with structured logging and the usual Go lint/modernize gates. Nest remained the behavioural oracle during migration. The same window closed a reliability contract: startup policies, atomic claims and leases for simulation and broadcast, idempotent notifications with shared dedupe keys, delivery ledger semantics for ambiguous external sends, and enqueue outcomes that distinguish fresh work from duplicates still in flight. In simple terms, background work gained a home built for long-running correctness, and “run it again” stopped meaning “do it twice.”

The challenges were parity and dual-runtime risk. Porting every side effect is tedious; leaving Nest and Go both willing to consume the same queue is catastrophic. Ownership gates and staging caution were the load-bearing choices — slower than flipping a single flag, safer than inventing a second universe of jobs. The strength of Go here is predictable workers and clearer ops boundaries; the drawback is two languages until Nest’s consumer runtime could finally leave.

Paths not taken included rewriting Nest processors “harder,” spawning match-sim as a Nest child process forever, or cutting over all queues on merge day. A Nest-only push would not have fixed the operational shape we wanted; CLI spawn forever couples deploy size to engine binaries Nest should not own; instant full cutover would have skipped the ownership ledger that made rollback thinkable.

What it unlocked was Nest as the door rather than the engine room — and a week of cup reconciliation and observability work that assumed Go already held the tick.

← All entries