Graceful shutdown via trap_exit and terminate/2

Before the code: what graceful shutdown actually means

Picture a restaurant at closing time. The good waiter does not yell stop and dump plates on the floor. They stop seating new guests, let the people already eating finish, then turn the lights off. That is graceful shutdown for a server. When the operating system sends a stop signal, you want the server to stop accepting new connections, let the writes already in flight finish, then quit. On the BEAM, OTP already gives you most of this for free. You opt into the cleanup with Process.flag(:trap_exit, true) and a terminate/2 callback, and OTP handles the rest.

Stop accepting, drain, exit

A clean shutdown has three phases: stop accepting new work, let in-flight work finish, then exit the process. On the BEAM it is mostly the supervisor handing each child a calm exit signal.

Quiz: Quiz

Loading practice…

Why is this Elixir's step 9? Because OTP already gives us what other languages had to engineer. The whole step is one Process.flag call plus one terminate/2 callback.

09-graceful-shutdown/server.exs
elixir
def init(_) do
  Process.flag(:trap_exit, true)
  store = case File.read(@rdb_path) do
    {:ok, bin} -> :erlang.binary_to_term(bin)
    {:error, _} -> %{}
  end
  {:ok, store}
end

def terminate(reason, state) do
  IO.puts("[shutdown] terminate received (#{inspect(reason)})")
  tmp = "#{@rdb_path}.tmp"
  File.write!(tmp, :erlang.term_to_binary(state))
  File.rename!(tmp, @rdb_path)
  :ok
end

init enables trap_exit. terminate/2 fires on shutdown and snapshots.

Where is the in-flight semaphore from the other siblings? It is not needed. Every connection is its own BEAM process. The supervisor's shutdown timeout (default 5s) lets each child finish its current call. OTP does the bookkeeping.

When the supervisor sends a normal shutdown. In production: Application.stop -> Supervisor sends :shutdown -> each child runs terminate/2. In iex: you may need to press Ctrl+C twice; the IEx shell traps the first one. In a real release (mix release), bin/myapp stop triggers a graceful shutdown cleanly.

Quiz: Quiz

Loading practice…