Elixir v1.0.4 ships with two new important options for new projects. If you generate a new application with
mix new, you will see in your
[build_embedded: Mix.env == :prod, start_permanent: Mix.env == :prod]
Although those options were originally meant to be in Elixir v1.1, we have decided to bring them into v1.0.4 and do a new release. In this post, we will explain why.
One of Elixir’s most important features are protocols. Protocols allow developers to write code that accept any data type, dispatching to the appropriate implementation of the protocol at runtime. For example:
defprotocol JSON do def encode(data) end defimpl JSON, for: List do def encode(list) do # ... end end
However, in order to play nicely with the dynamic nature of the Erlang VM where modules can be loaded at any time by the VM, as well as any protocol implementation, protocols need to check on every dispatch if a new implementation is available for any given data type.
While we would gladly pay this price in development as it gives developers flexibility, we would like to avoid such in production as deployments gives us a consolidated view of all modules in the system allowing us to skip those runtime checks. For this reason, Elixir provides a feature called protocol consolidation, that consolidates all protocols with their implementations, giving protocols a fast dispatch to use in production.
Prior to Elixir v1.0.4, protocol consolidation had to be manually invoked by calling
mix compile.protocols, which would consolidate protocols into a predefined directory, and this directory had to be explicitly added to your load path when starting your project. Due to the manual nature of such commands, a lot of developers ended-up not running them in production, or were often confused when doing so.
For this reason, Elixir v1.0.4 introduces a
:consolidate_protocols option to your projects which will take care of consolidating and loading all protocols before your application starts. This option is also set to true when
:build_embedded is true.
When compiling your projects, Elixir will place all compiled artifacts into the
_build/ dev/ lib/ your_app/ ebin/ priv/ dep1/ dep2/ test/ prod/
Many of those applications and dependencies have artifacts in their source that are required during runtime. Such artifacts are placed in the
priv directory in Elixir applications. By default, Elixir will symlink to their source directories during development.
In production, though, we could copy those contents to avoid symlink traversal, embedding all relevant files to run your application into the
_build directory, without a need for their sources.
That’s what the
:build_embedded option does and it defaults to true in production for new applications.
Elixir code is packaged into applications. For example, each entry we saw under
_build/dev/lib above is a different application. When an application is started, it can be started in one of the three following modes:
permanent– if app terminates, all other applications and the entire node are also terminated
transient– if app terminates with :normal reason, it is reported but no other applications are terminated. If a transient application terminates abnormally, all other applications and the entire node are also terminated
temporary– if app terminates, it is reported but no other applications are terminated
The default mode is temporary, which again, makes sense for development. For example, our test library called ExUnit, is also an application. If the application being tested crashes, we still want the ExUnit application to continue running in order to finish all tests and generate the proper reports. In this case, you definitely do not want your application to run as permanent.
However, in production, once your application crashes permanently, beyond recovery, we want the whole node to terminate, otherwise whatever you have monitoring your application at the operating system level won’t notice any change.
:start_permanent option starts your application as
:permanent and it defaults to true in production for new applications.
Those new options have been introduced into Elixir v1.0.4 because they are very important for running Elixir in production. They bring more performance and stability to your Elixir-based systems.
There are other smaller changes in this release, like support for Erlang 17.5 and 18.0-rc1, as well as bug fixes. Check the release notes for more information and enjoy!