Elixir/Erlang Hot Swapping Code
As the naming might suggest, “appups” and “relups” are the “upgrade”
versions of applications and releases, respectively. Appups describe how
to take a single application and upgrade its modules, specifically, it
will have instructions for upgrading modules that require “extras”. or,
if we are upgrading supervisors, for example, the Appup will have the
correct instructions for adding and removing child processes.
Before we examine some examples of these files, let’s first look at the
type specification for each.
Here is the syntax structure for the appup
resource file:
{Vsn, [{UpFromVsn, Instructions}, ...], [{DownToVsn, Instructions}, ...]}.
The first element of the triple is the version we are either upgrading to or
downgrading from. The second element is a keyword list of upgrade instructions
keyed by the version the application would be coming from. Similarly, the
third element is a keyword list of downgrade instructions keyed by the version
the application will downgrade to. For more information about the types
themselves, see the SASL documentation.
Now that we have seen the syntax, let’s look at an example of the appup
resource file for the octochat application generated using
distillery:
± cat rel/octochat/lib/octochat-0.2.1/ebin/octochat.appup {"0.2.1", [{"0.2.0",[{load_module,'Elixir.Octochat.Echo',[]}]}], [{"0.2.0",[{load_module,'Elixir.Octochat.Echo',[]}]}]}.
Comparing this to the syntax structure above, we see that we have a Vsn
element of "0.2.1"
, we have a {UpFromVsn, Instructions}
pair:
[{"0.2.0",[{load_module,'Elixir.Octochat.Echo',[]}]}]
, and we have a single
{DownToVsn, Instructions}
pair:
[{"0.2.0",[{load_module,'Elixir.Octochat.Echo',[]}]}]
.
The instructions themselves tell us what exactly is required to go from one
version to the another. Specifically, in this example, to upgrade, we need to
“load” the Octochat.Echo
module into the VM. Similarly, the instructions to
downgrade are the same. For a semantically versioned
project, this is an understandably small change.
It’s worth noting the instructions found in the .appup
files are
usually high-level instructions, thus, load_module
covers both the
loading of object code into memory and the suspend, replace, resume
process of upgrading applications.
Next, let’s look at the syntax structure of a relup
resource file:
{Vsn, [{UpFromVsn, Descr, Instructions}, ...], [{DownToVsn, Descr, Instructions}, ...]}.
This should look familiar. It’s essentially the exact same as the
.appup
file. However, there’s an extra term, Descr
. The Descr
field can be used as part of the version identification, but is
optional. Otherwise, the syntax of this file is the same as the
.appup
.
Now, let’s look at an example relup
file for the same release of
octochat:
± cat rel/octochat/releases/0.2.1/relup {"0.2.1", [{"0.2.0",[], [{load_object_code,{octochat,"0.2.1",['Elixir.Octochat.Echo']}}, point_of_no_return, {load,{'Elixir.Octochat.Echo',brutal_purge,brutal_purge}}]}], [{"0.2.0",[], [{load_object_code,{octochat,"0.2.0",['Elixir.Octochat.Echo']}}, point_of_no_return, {load,{'Elixir.Octochat.Echo',brutal_purge,brutal_purge}}]}]}.
This file is a little more dense, but still adheres to the basic triple syntax
we just examined. Let’s take a closer look at the upgrade instructions:
[{load_object_code,{octochat,"0.2.1",['Elixir.Octochat.Echo']}}, point_of_no_return, {load,{'Elixir.Octochat.Echo',brutal_purge,brutal_purge}}]
The first instruction,
{load_object_code,{octochat,"0.2.1",['Elixir.Octochat.Echo']}}
, tells the
release handler to load into memory the new
version of the “Octochat.Echo” module, specifically the one associated with
version “0.2.1”. But this instruction will not instruct the release handler to
(re)start or replace the existing module yet. Next, point_of_no_return
, tells
the release handler that failure beyond this point is fatal, if the upgrade
fails after this point, the system is restarted from the old release version
(appup documentation). The final instruction,
{load,{'Elixir.Octochat.Echo',brutal_purge,brutal_purge}}
, tells the release
handler to replace the running version of the module and use the newly loaded
version.
For more information regarding burtal_purge
, check out the “PrePurge” and
“PostPurge” values in the appup documentation.
Similar to the .appup
file, the third element in the triple describes to the
release handler how to downgrade the release as well. The version numbers in
this case make this a bit more obvious as well, however, the steps are
essentially the same.