I’ve spent some time understanding how to do hot code reloading with releases built using mix release, and here I’d like to detail the steps needed, in hopes that it will help someone.
So, in order to make hot-reloadable release you need:
- Write an appup file (the Erlang’s Appup cookbook is a great resource for that: Appup Cookbook — Erlang System Documentation v27.0.1).
- Tweak the release generated by
mix release, by copying the .rel & .appup files into expected places and generating the relup file. This can be done by hand, but I’ve wrote a simple function that can do that right inside themix releasetask:
def project do
[
releases: [
app_name: [
include_executables_for: [:unix],
steps: [:assemble, &release_fixup_step/1, :tar],
],
],
...
]
end
defp release_fixup_step(release) do
releases_dir = Path.join(release.path, "releases")
rel_file = Path.join([releases_dir, release.version, "#{release.name}.rel"])
:ok = :release_handler.create_RELEASES(releases_dir, rel_file, [])
# Yes, we have three copies of a same file in the same place.
# This is necessary to appease the release_handler.
File.cp!(rel_file, Path.join([releases_dir, release.version, "#{release.name}-#{release.version}.rel"]))
File.cp!(rel_file, Path.join([releases_dir, "#{release.name}-#{release.version}.rel"]))
# Copy appup file into the correct location and generate the relup.
appup_file = Path.join("appups", "#{release.version}.appup")
if File.exists?(Path.join("appups", "#{release.version}.appup")) do
File.cp!(
appup_file,
Path.join([release.path, "lib", "#{release.name}-#{release.version}", "ebin", "#{release.name}.appup"])
)
{:ok, appup} = :file.consult(appup_file)
[{appup_release_version, [{version_up_from, _}], [{version_down_to, _}]}] = appup
if appup_release_version != to_charlist(release.version) do
raise "Unexpected version in appup: #{appup_release_version} (expected #{release.version})"
end
if version_up_from != version_down_to do
raise "Unexpected versions in appup instructions: #{version_up_from} != #{version_down_to}"
end
:systools.make_relup(
~c"#{release.name}-#{release.version}",
[~c"#{release.name}-#{version_up_from}"],
[~c"#{release.name}-#{version_down_to}"],
path: [to_charlist(Path.join(release.path, "releases/*")), to_charlist(Path.join(release.path, "lib/*/ebin"))],
outdir: to_charlist(release.version_path)
)
end
release
end
Now, after running mix release you will get a release archive in _build/<env>/app_name-<version>.tar.gz.
- Copy this archive into the
releases/directory of your running release. - Connect to the Iex shell of the running release.
- Carefully run the commands:
:release_handler.unpack_release(~c"app_name-<version>")
:release_handler.install_release(~c"<version>")
:release_handler.make_permanent(~c"<version>")






















