Hot code reloading for development (recompile-on-save) has issues, but production hot code loading for zero-downtime deployments is still a core BEAM strength and what this article focuses on.
To be fair, I think most apps don't need zero-downtime deployments in the telcom sense.
Most host have blue-green deploy options which reduce downtime and there are fewer corner cases to deal with.
I find local recompile very useful for prototyping in development mode. So much so that I have a keyboard shortcut to trigger a recompile. (I don't like recompile on save.)
We run a large distributed cluster (currently 4 DCs spanning the US) and use hot code reload for live patches when needed and rolling deployments for our standard releases.
I'm not using this to update the app itself - which is a docker container that gets updated when I push a new version. I'm simply using the BEAM's code loading capabilities to add client-specific parts to the app while it is running. They are part of the monorepo (and thus part of the app at dev time), but get stripped at build-time so they can be selectively loaded later.
Elixir removed a jankier https://www.erlang.org/doc/apps/sasl/appup.html mechanism that defined how state is upgraded or downgraded, while watching a directory and recompiling a module automatically or manually from the repl is still common
> while watching a directory and recompiling a module automatically or manually from the repl is still common
That makes it sound like the "hot" part has been removed then, and it's just basically a "live reload" rather than "hot code loading", is that right? There is no persistent state and you get a fresh one after the automatic compilation happened?
I've used utility functions in Erlang where I make changes, then compile and load all modified modules...
It's absolutely hot loading, there's persistent state, any fully qualified function calls run in the newest module. The gen_server pattern always calls into your behavior module with fully qualified calls, so those are pretty easy to get into new code at a reasonable time. If you write your own service loop, it's pretty common to call ?MODULE:loop() to enable hotloading there too.
There's footguns; hotloading is a way to make rapid changes to your system, but sometimes rapid changes isn't what's needed and sometimes the rapid change you make is to go from a partially broken system to a fully broken system. But, there's a virtuous circle when you can make production changes quickly, because you can make a small change and observe and make many follow ups in a single day. With push processes that take a long time, you end up encouraged to make a bigger change one time, otherwise you spend all day waiting for traffic to move between old and new versions, or waiting for instances to deploy, etc.
no, for example if you are running a liveview in dev and recompiling your code the liveview does not lose its state and jumps into the new module, unless I'm mistaken.
queued messages stay around in the mailboxes, so no state is lost, but don't get migrated/transformed/versioned via the appup mechanism, unless you opt back into it via libraries for it like https://github.com/ausimian/castle
Overall, it's not widely used nor pushed (blue green deployments are now very common), but it still has interesting uses.
For instance, very high availability without blue-green (using a front-end that can be hot-patched), or... musical endeavors (such as live reloading code that generates music, on the go) https://youtu.be/_VgcUatTilU?si=DDfe4FN3Nw9OzRhF&t=122
Hot code reloading for development (recompile-on-save) has issues, but production hot code loading for zero-downtime deployments is still a core BEAM strength and what this article focuses on.
To be fair, I think most apps don't need zero-downtime deployments in the telcom sense.
Most host have blue-green deploy options which reduce downtime and there are fewer corner cases to deal with.
I find local recompile very useful for prototyping in development mode. So much so that I have a keyboard shortcut to trigger a recompile. (I don't like recompile on save.)
We run a large distributed cluster (currently 4 DCs spanning the US) and use hot code reload for live patches when needed and rolling deployments for our standard releases.
To add to this topic, people who do not know about erlang's hot code loading should watch this talk : https://www.youtube.com/watch?v=pQ0CvjAJXz4
A multi-DC running cluster where parts are progressively swapped at runtime. No database, only OTP.
I'm not using this to update the app itself - which is a docker container that gets updated when I push a new version. I'm simply using the BEAM's code loading capabilities to add client-specific parts to the app while it is running. They are part of the monorepo (and thus part of the app at dev time), but get stripped at build-time so they can be selectively loaded later.
Elixir removed a jankier https://www.erlang.org/doc/apps/sasl/appup.html mechanism that defined how state is upgraded or downgraded, while watching a directory and recompiling a module automatically or manually from the repl is still common
> while watching a directory and recompiling a module automatically or manually from the repl is still common
That makes it sound like the "hot" part has been removed then, and it's just basically a "live reload" rather than "hot code loading", is that right? There is no persistent state and you get a fresh one after the automatic compilation happened?
I've used utility functions in Erlang where I make changes, then compile and load all modified modules...
It's absolutely hot loading, there's persistent state, any fully qualified function calls run in the newest module. The gen_server pattern always calls into your behavior module with fully qualified calls, so those are pretty easy to get into new code at a reasonable time. If you write your own service loop, it's pretty common to call ?MODULE:loop() to enable hotloading there too.
There's footguns; hotloading is a way to make rapid changes to your system, but sometimes rapid changes isn't what's needed and sometimes the rapid change you make is to go from a partially broken system to a fully broken system. But, there's a virtuous circle when you can make production changes quickly, because you can make a small change and observe and make many follow ups in a single day. With push processes that take a long time, you end up encouraged to make a bigger change one time, otherwise you spend all day waiting for traffic to move between old and new versions, or waiting for instances to deploy, etc.
no, for example if you are running a liveview in dev and recompiling your code the liveview does not lose its state and jumps into the new module, unless I'm mistaken.
queued messages stay around in the mailboxes, so no state is lost, but don't get migrated/transformed/versioned via the appup mechanism, unless you opt back into it via libraries for it like https://github.com/ausimian/castle
Overall, it's not widely used nor pushed (blue green deployments are now very common), but it still has interesting uses.
For instance, very high availability without blue-green (using a front-end that can be hot-patched), or... musical endeavors (such as live reloading code that generates music, on the go) https://youtu.be/_VgcUatTilU?si=DDfe4FN3Nw9OzRhF&t=122
That seems more about loading dynamic code.