Application behaviour
A module for working with applications and defining application callbacks.
In Elixir (actually, in Erlang/OTP), an application is a component implementing some specific functionality, that can be started and stopped as a unit, and which can be re-used in other systems.
Applications are defined with an application file named APP.app
where APP
is the application name, usually in underscore_case
. The application file must reside in the same ebin
directory as the compiled modules of the application.
In Elixir, Mix is responsible for compiling your source code and generating your application .app
file. Furthermore, Mix is also responsible for configuring, starting and stopping your application and its dependencies. For this reason, this documentation will focus on the remaining aspects of your application: the application environment and the application callback module.
You can learn more about Mix generation of .app
files by typing mix help compile.app
.
Application environment
Once an application is started, OTP provides an application environment that can be used to configure the application.
Assuming you are inside a Mix project, you can edit the application/0
function in the mix.exs
file to the following:
def application do [env: [hello: :world]] end
In the application function, we can define the default environment values for our application. By starting your application with iex -S mix
, you can access the default value:
Application.get_env(:APP_NAME, :hello) #=> :world
It is also possible to put and delete values from the application value, including new values that are not defined in the environment file (although this should be avoided).
Keep in mind that each application is responsible for its environment. Do not use the functions in this module for directly accessing or modifying the environment of other applications (as it may lead to inconsistent data in the application environment).
Application module callback
Often times, an application defines a supervision tree that must be started and stopped when the application starts and stops. For such, we need to define an application module callback. The first step is to define the module callback in the application definition in the mix.exs
file:
def application do [mod: {MyApp, []}] end
Our application now requires the MyApp
module to provide an application callback. This can be done by invoking use Application
in that module and defining a start/2
callback, for example:
defmodule MyApp do use Application def start(_type, _args) do MyApp.Supervisor.start_link() end end
start/2
typically returns {:ok, pid}
or {:ok, pid, state}
where pid
identifies the supervision tree and state
is the application state. args
is the second element of the tuple given to the :mod
option.
The type
argument passed to start/2
is usually :normal
unless in a distributed setup where application takeovers and failovers are configured. This particular aspect of applications is explained in more detail in the OTP documentation:
A developer may also implement the stop/1
callback (automatically defined by use Application
) which does any application cleanup. It receives the application state and can return any value. Note that shutting down the supervisor is automatically handled by the VM.
Summary
Types
Functions
- app_dir(app)
-
Gets the directory for app
- app_dir(app, path)
-
Returns the given path inside
app_dir/1
- delete_env(app, key, opts \\ [])
-
Deletes the
key
from the givenapp
environment - ensure_all_started(app, type \\ :temporary)
-
Ensures the given
app
and its applications are started - ensure_started(app, type \\ :temporary)
-
Ensures the given
app
is started - fetch_env(app, key)
-
Returns the value for
key
inapp
’s environment in a tuple - fetch_env!(app, key)
-
Returns the value for
key
inapp
’s environment - format_error(reason)
-
Formats the error reason returned by
start/2
,ensure_started/2
,stop/1
,load/1
andunload/1
, returns a string - get_all_env(app)
-
Returns all key-value pairs for
app
- get_application(module)
-
Gets the application for the given module
- get_env(app, key, default \\ nil)
-
Returns the value for
key
inapp
’s environment - load(app)
-
Loads the given
app
- loaded_applications()
-
Returns a list with information about the applications which have been loaded
- put_env(app, key, value, opts \\ [])
-
Puts the
value
inkey
for the givenapp
- spec(app)
-
Returns the spec for
app
- spec(app, key)
-
Returns the value for
key
inapp
’s specification - start(app, type \\ :temporary)
-
Starts the given
app
- started_applications(timeout \\ 5000)
-
Returns a list with information about the applications which are currently running
- stop(app)
-
Stops the given
app
- unload(app)
-
Unloads the given
app
Callbacks
- start(start_type, start_args)
-
Called when an application is started
- stop(state)
-
Called when an application is stopped
Types
app()
app() :: atom()
key()
key() :: atom()
start_type()
start_type() :: :permanent | :transient | :temporary
state()
state() :: term()
value()
value() :: term()
Functions
app_dir(app)
app_dir(app()) :: String.t()
Gets the directory for app.
This information is returned based on the code path. Here is an example:
File.mkdir_p!("foo/ebin") Code.prepend_path("foo/ebin") Application.app_dir(:foo) #=> "foo"
Even though the directory is empty and there is no .app
file it is considered the application directory based on the name “foo/ebin”. The name may contain a dash -
which is considered to be the app version and it is removed for the lookup purposes:
File.mkdir_p!("bar-123/ebin") Code.prepend_path("bar-123/ebin") Application.app_dir(:bar) #=> "bar-123"
For more information on code paths, check the Code
module in Elixir and also Erlang’s :code
module.
app_dir(app, path)
app_dir(app(), String.t() | [String.t()]) :: String.t()
Returns the given path inside app_dir/1
.
delete_env(app, key, opts \\ [])
delete_env(app(), key(), [timeout: timeout(), persistent: boolean()]) :: :ok
Deletes the key
from the given app
environment.
See put_env/4
for a description of the options.
ensure_all_started(app, type \\ :temporary)
ensure_all_started(app(), start_type()) :: {:ok, [app()]} | {:error, {app(), term()}}
Ensures the given app
and its applications are started.
Same as start/2
but also starts the applications listed under :applications
in the .app
file in case they were not previously started.
ensure_started(app, type \\ :temporary)
ensure_started(app(), start_type()) :: :ok | {:error, term()}
Ensures the given app
is started.
Same as start/2
but returns :ok
if the application was already started. This is useful in scripts and in test setup, where test applications need to be explicitly started:
:ok = Application.ensure_started(:my_test_dep)
fetch_env(app, key)
fetch_env(app(), key()) :: {:ok, value()} | :error
Returns the value for key
in app
’s environment in a tuple.
If the configuration parameter does not exist, the function returns :error
.
fetch_env!(app, key)
fetch_env!(app(), key()) :: value() | no_return()
Returns the value for key
in app
’s environment.
If the configuration parameter does not exist, raises ArgumentError
.
format_error(reason)
format_error(any()) :: String.t()
Formats the error reason returned by start/2
, ensure_started/2
, stop/1
, load/1
and unload/1
, returns a string.
get_all_env(app)
get_all_env(app()) :: [{key(), value()}]
Returns all key-value pairs for app
.
get_application(module)
get_application(atom()) :: atom() | nil
Gets the application for the given module.
The application is located by analyzing the spec of all loaded applications. Returns nil
if the module is not listed in any application spec.
get_env(app, key, default \\ nil)
get_env(app(), key(), value()) :: value()
Returns the value for key
in app
’s environment.
If the configuration parameter does not exist, the function returns the default
value.
load(app)
load(app()) :: :ok | {:error, term()}
Loads the given app
.
In order to be loaded, an .app
file must be in the load paths. All :included_applications
will also be loaded.
Loading the application does not start it nor load its modules, but it does load its environment.
loaded_applications()
loaded_applications() :: [tuple()]
Returns a list with information about the applications which have been loaded.
put_env(app, key, value, opts \\ [])
put_env(app(), key(), value(), [timeout: timeout(), persistent: boolean()]) :: :ok
Puts the value
in key
for the given app
.
Options
-
:timeout
- the timeout for the change (defaults to 5000ms) -
:persistent
- persists the given value on application load and reloads
If put_env/4
is called before the application is loaded, the application environment values specified in the .app
file will override the ones previously set.
The persistent option can be set to true
when there is a need to guarantee parameters set with this function will not be overridden by the ones defined in the application resource file on load. This means persistent values will stick after the application is loaded and also on application reload.
spec(app)
spec(app()) :: [{key(), value()}] | nil
Returns the spec for app
.
The following keys are returned:
- :description
- :id
- :vsn
- :modules
- :maxP
- :maxT
- :registered
- :included_applications
- :applications
- :mod
- :start_phases
Note the environment is not returned as it can be accessed via fetch_env/2
. Returns nil
if the application is not loaded.
spec(app, key)
spec(app(), key()) :: value() | nil
Returns the value for key
in app
’s specification.
See spec/1
for the supported keys. If the given specification parameter does not exist, this function will raise. Returns nil
if the application is not loaded.
start(app, type \\ :temporary)
start(app(), start_type()) :: :ok | {:error, term()}
Starts the given app
.
If the app
is not loaded, the application will first be loaded using load/1
. Any included application, defined in the :included_applications
key of the .app
file will also be loaded, but they won’t be started.
Furthermore, all applications listed in the :applications
key must be explicitly started before this application is. If not, {:error, {:not_started, app}}
is returned, where app
is the name of the missing application.
In case you want to automatically load and start all of app
’s dependencies, see ensure_all_started/2
.
The type
argument specifies the type of the application:
-
:permanent
- ifapp
terminates, all other applications and the entire node are also terminated. -
:transient
- ifapp
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
- ifapp
terminates, it is reported but no other applications are terminated (the default).
Note that it is always possible to stop an application explicitly by calling stop/1
. Regardless of the type of the application, no other applications will be affected.
Note also that the :transient
type is of little practical use, since when a supervision tree terminates, the reason is set to :shutdown
, not :normal
.
started_applications(timeout \\ 5000)
started_applications(timeout()) :: [tuple()]
Returns a list with information about the applications which are currently running.
stop(app)
stop(app()) :: :ok | {:error, term()}
Stops the given app
.
When stopped, the application is still loaded.
unload(app)
unload(app()) :: :ok | {:error, term()}
Unloads the given app
.
It will also unload all :included_applications
. Note that the function does not purge the application modules.
Callbacks
start(start_type, start_args)
start(start_type(), start_args :: term()) :: {:ok, pid()} | {:ok, pid(), state()} | {:error, reason :: term()}
Called when an application is started.
This function is called when an the application is started using Application.start/2
(and functions on top of that, such as Application.ensure_started/2
). This function should start the top-level process of the application (which should be the top supervisor of the application’s supervision tree if the application follows the OTP design principles around supervision).
start_type
defines how the application is started:
-
:normal
- used if the startup is a normal startup or if the application is distributed and is started on the current node because of a failover from another mode and the application specification key:start_phases
is:undefined
. -
{:takeover, node}
- used if the application is distributed and is started on the current node because of a failover on the nodenode
. -
{:failover, node}
- used if the application is distributed and is started on the current node because of a failover on nodenode
, and the application specification key:start_phases
is not:undefined
.
start_args
are the arguments passed to the application in the :mod
specification key (e.g., mod: {MyApp, [:my_args]}
).
This function should either return {:ok, pid}
or {:ok, pid, state}
if startup is successful. pid
should be the PID of the top supervisor. state
can be an arbitrary term, and if omitted will default to []
; if the application is later stopped, state
is passed to the stop/1
callback (see the documentation for the stop/1
callback for more information).
use Application
provides no default implementation for the start/2
callback.
stop(state)
stop(state()) :: term()
Called when an application is stopped.
This function is called when an application has stopped, i.e., when its supervision tree has been stopped. It should do the opposite of what the start/2
callback did, and should perform any necessary cleanup. The return value of this callback is ignored.
state
is the return value of the start/2
callback or the return value of the prep_stop/1
function if the application module defines such a function.
use Application
defines a default implementation of this function which does nothing and just returns :ok
.
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.4.5/Application.html