Member-only story
How We Accidentally Built a Fork Bomb in Go
When goroutine spawning goes unchecked
We didn’t set out to bring down production.
But in hindsight, the code we shipped might as well have been a fork bomb.
Not the kind you type into a Linux shell as a prank (:(){ :|:& };:), but a Go-flavored version: unbounded goroutine spawning that multiplied until the service collapsed under its own weight.
The Innocent Beginning
It started with a seemingly harmless retry loop.
We had a worker function responsible for processing jobs off a queue. If a job failed, we wanted to retry it in the background without blocking the main loop. Easy, right?
func process(job Job) {
if err := doWork(job); err != nil {
go process(job) // retry in background
}
}This looked clever.
It was simple.
It was also the start of our fork bomb.
The Explosion
Here’s what actually happened:
- Job fails once → spawns a new goroutine.
- That retry fails → spawns another goroutine.
- Both the old and the new goroutine are now live.






