Runtime hot-code upgrade support for Elixir releases.
Forecastle prepares releases at build time; Castle manages versions on the deployed node. It unpacks, installs, commits and removes releases, resolving a target's config providers before install or commit.
Call customize/1 from the release definition in mix.exs. The remaining
public functions back the bin/castle commands.
Successful commands print their result and return :ok. Castle refusals and
:release_handler errors raise Castle.Error, giving bin/castle a non-zero
exit status. Other exceptions, throws and exits propagate unchanged. Treat any
raise over rpc as a failed command.
Commands that modify a deployment require the VM's emulator root to match the
release root. This rejects include_erts: false and other layouts in which
:release_handler would modify a shared Erlang installation. The diagnostic
functions upgradable/0 and releases/0 remain available.
Summary
Functions
Makes vsn permanent, so that it is the version a restart boots into.
Makes a Mix release Castle-capable.
Installs vsn and makes it the version the system is running.
Lists the releases the system knows of, and the status of each.
Removes vsn from the system, and deletes what nothing else is using.
Confirms that vsn is the release the system is running, and has finished
booting.
Unpacks a release tarball into the deployment, and reports the version.
Checks whether the running node has a valid release record for upgrades.
Functions
@spec commit(String.t()) :: :ok
Makes vsn permanent, so that it is the version a restart boots into.
bin/castle commit [<vsn>] calls this function. Without a version, the command
selects the current release and exits non-zero when none is awaiting commit.
Castle resolves the target's config providers again before promotion, storing the configuration a boot at commit time would produce. An explicit commit of the permanent version still performs this step.
Raises Castle.Error if the configuration could not be expanded, or if the
version cannot be promoted. This includes staged, rolled-back, superseded and
unknown versions.
Makes a Mix release Castle-capable.
Adds Forecastle's build steps and returns the updated release options.
# mix.exs
defp releases do
[
my_app: fn ->
[
include_executables_for: [:unix],
steps: [:assemble, :tar]
]
|> Castle.customize()
end
]
endDefine the release with fn -> ... end so Mix evaluates it after Castle has
been compiled.
Steps
Existing steps retain their order. If :steps is absent, this function uses
[:assemble, :tar]. It preserves an explicit list and warns when the
list has no :tar.
Forecastle generates the relup after custom steps that change the release and
immediately before :tar. If a custom step packages the release without
:tar, place &Forecastle.generate_relup/1 immediately before that step.
Split steps that both modify and package the release. A step after :tar must
not modify or repackage it.
Upgrades
upgrade_from: names the supported source releases:
my_app: fn ->
[
include_executables_for: [:unix],
upgrade_from: ["tar:artifacts/my_app-1.0.0.tar.gz"]
]
|> Castle.customize()
endA baseline may be a shipped tar: archive, an assembled rel: release or a
ref: git ref. A path without a prefix means rel:. Forecastle generates
both directions for every baseline. Prefer tar: when the shipped artifact
is available because a rebuilt baseline may differ from the deployed release.
Forecastle validates upgrade_from:. It rejects malformed or duplicate
values and a project-root relup supplied alongside the option. Omitting the
option skips relup generation.
The project must also provide:
- An appup for each owned application upgraded in place, configured with the
:appupproject key andcompilers: Mix.compilers() ++ [:appup]. Seemix help castle.relupfor the rules. - A relup generated from
upgrade_from:, or one generated bymix castle.relupand left in the project root. include_executables_for: [:unix].
Forecastle appends Castle's setup to the generated env.sh or to a custom
rel/env.sh.eex.
Installs vsn and makes it the version the system is running.
bin/castle install <vsn> calls this function after unpack/1 stages the
version.
Castle checks the deployment and release record, resolves the target's config
providers in a temporary VM, and prepares any emulator-restart marker before
calling :release_handler.install_release/1.
A hot upgrade reports the new and previous running versions. An upgrade that
restarts the emulator reports that the version was installed and remains
provisional. bin/castle install then polls running/1 until the target has
finished booting. Automation that calls install/1 over rpc must perform
the same check.
The installed version remains provisional until commit/1. An ordinary
restart before commit boots the previous permanent version. A
restart_emulator transition boots the target for its installation restart,
but later restarts still use the permanent version until commit.
Castle serialises installs on the local Erlang node. A pending restart install owns its launcher marker and blocks another restart install from replacing it.
The four extra arguments
install/1 is the supported form. The defaulted arguments on install/2
through install/5 are test seams, not deployment options.
@spec releases() :: :ok
Lists the releases the system knows of, and the status of each.
bin/castle releases calls this function. It prints one line per release with
its :release_handler status: permanent, current, unpacked or old.
unpacked includes staged releases and releases returned to that state after
a failed or rolled-back install. A node with no known releases prints nothing.
This read-only command remains available when mutating commands are refused.
@spec remove(String.t()) :: :ok
Removes vsn from the system, and deletes what nothing else is using.
bin/castle remove <vsn> calls this function. It removes the version directory,
unreferenced application directories, and an emulator directory unused by any
remaining release.
Raises Castle.Error for the permanent version or an unknown version.
@spec running(String.t()) :: :ok
Confirms that vsn is the release the system is running, and has finished
booting.
Success prints nothing. A different running version or an incomplete boot
raises Castle.Error with the current state.
bin/castle install polls this function. It accepts the current release, or
the permanent release when no release is current, after the boot script
reaches its started marker.
@spec unpack(String.t()) :: :ok
Unpacks a release tarball into the deployment, and reports the version.
bin/castle unpack <vsn> calls this function. Place
<release-name>-<vsn>.tar.gz in the deployment's releases directory first.
The command extracts the applications and records the version as unpacked.
It does not change the running version.
Raises Castle.Error if the node cannot be upgraded from. See
upgradable/0. RELDIR and the SASL releases_dir option are not supported;
see issue #23.
@spec upgradable() :: :ok
Checks whether the running node has a valid release record for upgrades.
bin/castle upgradable calls this function. Success prints nothing. A node
using a record synthesised by :release_handler raises Castle.Error with
recovery instructions.
unpack/1 and install/1 perform the same check when they act. A prior call
to upgradable/0 is diagnostic only.
The release-record file is normally <root>/releases/RELEASES. RELDIR or
the SASL releases_dir option can move the file read by :release_handler.