Reading — step 1 of 7
Learn
Hot code reload is Erlang's signature feature: replace a running module's code without stopping the VM. Foundation of Ericsson's nine-nines uptime.
How it works
The BEAM keeps TWO versions of each loaded module:
- The current version (latest loaded)
- The old version (the one before)
Processes execute the version they were running when called. New calls into the module use the current version.
Reloading at the shell
%% Compile and load:
1> c(my_mod).
{ok, my_mod}
%% Module's code is now updated. Existing processes finish their current call
%% with the OLD code, then their NEXT call uses the new code.
For a long-lived gen_server: when you reload its module, the next message it processes uses the new code. Mid-call work continues with the old.
Forcing a process to use new code
The canonical pattern:
handle_call(Msg, From, State) ->
%% normal handling
?MODULE:handle_call(Msg, From, State). %% fully-qualified call
The fully-qualified call (?MODULE:fn(...)) ALWAYS goes through the latest version. Internal calls (fn(...) without prefix) stay with the version the process was loaded with.
In gen_server's loop, the framework does fully-qualified calls into your callbacks — so reloading your module immediately affects new messages.
code:purge / code:soft_purge
The BEAM only allows TWO versions. Loading a third triggers a purge of the oldest:
code:soft_purge(my_mod). %% safe — fails if any process is still on old version
code:purge(my_mod). %% kills processes still on old version!
If a process is in the middle of a long call to the old version when a third version loads, purge will kill it. soft_purge returns false instead — letting you decide.
Code change callback (gen_server)
For sophisticated upgrades that need to migrate state:
code_change(OldVsn, State, _Extra) ->
%% Migrate State from OldVsn to current version
NewState = transform_state(OldVsn, State),
{ok, NewState}.
The OTP release tooling triggers code_change calls during in-place upgrades.
Release upgrades
For production: package upgrades as release packages (.tar.gz with new beams + upgrade scripts). The OTP release_handler applies them with proper sequencing — minimizing downtime.
Why this matters
WhatsApp and Ericsson's AXD301 switch use hot code reload to deploy code changes without dropping connections. Phone calls connected before the upgrade continue; new calls hit new code.
Most web stacks reach for blue-green deployments or rolling restarts. Erlang lets you do in-place upgrades when downtime really isn't an option.
When NOT to use
- Simple changes can be done with a restart — easier to reason about
- Schema migrations / large state shape changes — code_change has limits
- Upgrades that affect supervision tree shape — needs careful planning
Most Erlang/Elixir teams these days deploy via standard releases + restart. Hot reload is a tool for genuinely 24/7 systems where seconds of downtime aren't acceptable.
Common mistakes
- Internal calls vs fully-qualified —
f(X)(local) stays with old version after upgrade until the process restarts. Use?MODULE:f(X)if you want it to follow the latest. - purge over soft_purge — purge kills processes. soft_purge returns false; you handle the case.
- Skipping code_change for state changes — old state shape may not match new code. Migrate explicitly.
- Upgrading supervision trees — supervisor child_spec changes don't apply automatically; needs supervisor:terminate_child + start_child or restart.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…