rogach

rogach

How to: Tweak mix release to work with hot code reloading

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:

  1. Write an appup file (the Erlang’s Appup cookbook is a great resource for that: Appup Cookbook — Erlang System Documentation v27.0.1).
  2. 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 the mix release task:
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.

  1. Copy this archive into the releases/ directory of your running release.
  2. Connect to the Iex shell of the running release.
  3. Carefully run the commands:
:release_handler.unpack_release(~c"app_name-<version>")
:release_handler.install_release(~c"<version>")
:release_handler.make_permanent(~c"<version>")

Where Next?

Popular in Guides/Tuts Top

zenw0lf
Hello all! For those wanting to try your hands at Elixir / Phoenix, I wrote a comprehensive tutorial on doing a simple JSON API with sai...
New
marcelo
I wrote a small article on how to use current_user with coherence on Phoenix. There are already a couple of blogposts about it but I thin...
New
voltone
The EEF’s Security WG has released the first public draft of the Secure Coding and Deployment Hardening Guidelines for BEAM languages. “...
New
njwest
In the process of developing a Phx-based multiplayer experience, I found myself with so many browser tabs open with Elixir gaming resourc...
New
wfgilman
I'm writing up this quick "How to" because what I thought was going to be an easy implementation of a Plug to validate a webhook request ...
New
dmitriid
This is not a question, but a post for anyone who may need it in the future. Sometimes some browsers may mangle the filename if it’s non-...
New
dkuhlman
For those of you who might be interested in using ZeroMQ in Elixir, I converted the Erlang examples in the ZeroMQ “zguide” to Elixir. I ...
New
lukertty
Install web-mode and mmm-mode first and put this in your config file: (require 'mmm-mode) (require 'web-mode) (setq mmm-global-mode 'may...
New
fmcgeough
pipe into case? I use that fairly frequently…unless I’m misunderstanding what you’re wanting…could be… its still very early… str = "Hell...
New
water
I’ll post this here, It might help someone in the future. Feedback is greatly appreciated. I use it with direnv on NixOS, It should wor...
New

Other popular topics Top

lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
yurko
Here are few pieces of (common) Linux knowledge that we use for reasonably small one server apps. We use Ubuntu but this should work for ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

We're in Beta

About us Mission Statement