I Killed a Live Process on Purpose. It Came Back Faster Than I Could Type.

I found a process ID for order #6, and I whacked it. Good and dead. No warning, no graceful shutdown, just: gone.

Before I could even confirm it was fully whacked, it wasn’t. Same order, same state, brand new process, already up and running in the exact same spot.

Here’s the carnival I was playing in. The app is an order fulfillment dashboard; orders move through received, picking, packing, shipping, delivered, or land in an exception state if something breaks along the way. Full CRUD underneath, a real-time dashboard on top.

The first live moment happened right there on the dashboard. Click “Start” on an order, and this fires:

def handle_event("advance", %{"id" => id}, socket) do
  Order.Server.advance(id)
  {:noreply, socket}
end

That reaches a process handling that one order, which updates Postgres and then does this:

Phoenix.PubSub.broadcast(FulfillmentPipeline.PubSub, "orders", {:order_updated, updated_order})

Every browser with that dashboard open is listening for exactly that message:

def handle_info({:order_updated, updated_order}, socket) do
  {:noreply, assign(socket, orders: updated_orders)}
end

Status flips from received to picking, live, no reload, no polling loop, not one line of JavaScript. First time it worked, all I typed was “that fixed it.” Screenshot saved, moved on.

Then curiosity got the better of me. I wanted to know what happens if one of these processes just stopped existing, mid-request, no warning. I looked it up directly:

iex> [{pid, _}] = Registry.lookup(FulfillmentPipeline.Order.Registry, 6)
[{#PID<0.804.0>, nil}]

Then I did the thing you’re not supposed to do to something actively running:

iex> Process.exit(pid, :kill)

Whacked. No mercy, no cleanup.

Before I’d even finished typing my next line, I checked again:

iex> Registry.lookup(FulfillmentPipeline.Order.Registry, 6)
[{#PID<0.827.0>, nil}]

New PID. Same order. Same state. Picked up exactly where it left off, like the whole thing never happened. Because as far as the rest of the system was concerned, it hadn’t.

Here’s where this stopped being cute and started actually meaning something to me. Years ago, working at Intel, I was around teams building server RAS features: reliability, availability, serviceability. Entire hardware roadmaps, entire careers, chasing one goal: when something inevitably fails, however unglamorous or catastrophic, get it back up before anyone downstream notices. That was heavy, expensive, purpose-built engineering. Redundant components, failover paths, whole teams whose job was making sure a single point of failure never actually became a failure anyone felt.

Elixir just hands you a version of that discipline as the default. Not a feature you opt into. Not a subsystem you architect around. Just how a process works, out of the box, in a programming language, for free.

That’s the actual reason Exercism’s beginner track teaches processes this early, before regex, before structs, before enums. Three weeks ago I called that order backwards. It isn’t. It’s the language telling you up front what it was actually built for. Not syntax. Not convenience. Survivability, baked in below the level where you’d normally have to think about it.

I spent an afternoon trying to break something on purpose. I did not succeed. Whole engineering careers have been built chasing exactly that outcome, on hardware, at enormous cost. Elixir just gives it to you as a starting assumption, the moment you write your first GenServer.