benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Always use Releases

Correct if me I’m wrong, as best I can tell there aren’t any reasons to use mix run --no-halt in production vs releases. The marginal value always outweighs the marginal cost.

Marginal cost:

I’ve seen a lot of folks think that using releases means you MUST have a separate build vs application server/image/whatever. Heroku is a good example. You have a buildpack that contains Elixir and you compile your app with mix. What is the marginal cost of using releases on heroku?

Just one extra command! mix release, and then you run ./bin/myapp foreground instead of mix run --no-halt

Marginal value:

The marginal cost is low, what value do we get for that cost? There are some handy defaults surrounding remote console capability and heart (although frankly I’m a bit unclear about in what scenarios it’s going to act).

The PRIMARY value though is that releases will eagerly load all of your application and dependency code, whereas mix does so lazily.

For projects with many dependencies, there can be a massive latency spike when you first get requests / jobs that occur after starting your app with mix while it loads all your code. This can cause timeouts and error cascades. Sure the supervisor trees generally restart but there are situations where you exceed supervisor restarts per second limits and you end up having enormous portions of your app restart.

Conclusion.

Marginal cost / benefit: (handy defaults + EAGER CODE LOADING) / (one extra command)

Am I missing something? This seems like a hands down win for always using releases.

Most Liked

bitwalker

bitwalker

Leader

In my opinion, nobody should be building releases on their production host - they shouldn’t even have build tools installed on that host. You build your releases on your build host, and push those to production and then pull the trigger on rolling it out when you’re ready. This can be entirely automated, automated with some manual intervention, or done entirely manually.

I’ve set up and used different approaches depending on what I’m working on - with Docker/Kubernetes, there were dedicated hosts in the cluster which handled builds, and transfers of those images to the production hosts were super fast because they were colocated. Similarly, with a more traditional setup, we used Jenkins to build releases, and scp them to staging/production hosts and unpack them. My current project, we’re actually shipping virtual machines, so it’s an entirely different situation, but we’re still using releases (which are ultimately installed on the host via rpms).

The release tarballs are certainly a bit fat if you are including ERTS, but if your build and prod hosts are the same, then you don’t need to do that, and can omit ERTS, which is by far the bulk of the baggage the tarball carries.

17
Post #9
sasajuric

sasajuric

Author of Elixir In Action

I agree. I believe that OTP releases for systems (aka services that need to run continuously), and escripts for CLI tools are the way to go. Maybe there are some special cases, but can’t think of any.

I wouldn’t say that eager loading is the primary value, although it depends on the use case. I suspect that many systems are not that highly loaded for that to make a difference.

I do think that the defaults you mention, which allows remote logging and start the system as the node (so you can remote observe it) are more important.

But above all, I like the self-contained, isolated nature of the release. You won’t pickup some unexpected module from somewhere else (e.g. mix app is not included in OTP release, so less chances of invoking Mix.env at runtime), and you can easily run multiple different systems (services) with different versions of Elixir/Erlang.

I also agree that the cost is marginal. But even if it takes longer to properly setup your own build and deployment, it’s a one-off cost. Pay the price once, reap the benefits many times :slight_smile:

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Releases have no issue with environment variables. REPLACE_OS_VARS=true, and then in your config just foo: "${FOO}". We use identical images in staging and production, and do all config changes by specifying environment variables in our docker containers.

Where Next?

Popular in Guides/Tuts Top

bluegene
Hi guys, I’ve been on a personal journey to learn Elixir for the past two years. During this journey I’ve been using the spaced repetiti...
New
jswny
Hello everyone, I recently redesigned my entire deployment process for Phoenix apps based on Docker. I really like the strategy that I ca...
New
smpallen99
Did you know that IO.inspect/2 returns the the first argument and accepts a label option as a second argument. This makes it a perfect to...
New
hauleth
Some time ago someone suggested me to write article about how I have configured my Vim to work with Elixir, now there it is: https://med...
New
slouchpie
Warmest greetings, comrades. I recently started using :dns_cluster (GitHub - phoenixframework/dns_cluster: Simple DNS clustering for dis...
New
niku
I have published an elixir project with using Travis CI. I would like to share some tips & thoughts that I was getting through this ...
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
mhanberg
Hi! I recently finished adding authentication to my Phoenix API, so I wanted to share what I learned. I haven’t created authentication f...
New
KoviRobi
Hi, I’ve written the following to debug function calls, not sure if it’s useful for anyone else, and if so should I put it somewhere? i...
New
nietaki
Just a quick heads up: There seems to be a bug in Erlang/OTP 21.3, which can cause some errors when making http requests. If you’re using...
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
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
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

We're in Beta

About us Mission Statement