Spec-Zone.ru › Elixir 1.6

Приложение поведение

Модуль для работы с приложениями и определения обратных вызовов приложений.

В Elixir (на самом деле, в Erlang/OTP), приложение — это компонент, реализующий определённую функциональность, который может запускаться и останавливаться как единица и может повторно использоваться в других системах.

Приложения определяются с помощью файла приложения, названного APP.app, где APP — имя приложения, обычно в underscore_case. Файл приложения должен находиться в той же директории ebin, что и скомпилированные модули приложения. В Elixir, инструмент сборки Mix отвечает за компиляцию исходного кода и создание файла приложения .app. Вы можете узнать больше о генерации файлов .app, набрав mix help compile.app.

После компиляции приложения запуск вашей системы сводится к запуску текущего приложения и его зависимостей. В отличие от других языков, в Elixir нет процедуры main , которая отвечает за запуск вашей системы. Вместо этого вы запускаете одно или несколько приложений, каждое со своей логикой инициализации и завершения.

Приложения также предоставляют «среду приложения», которая обеспечивает один механизм для настройки долгоживущих приложений. Мы узнаем больше о средствах разработки, запуске и завершении работы, а также об среде приложения в следующих разделах.

Запуск и завершение

Запуск приложения выполняется с помощью «обратного вызова модуля приложения», который является модулем, определяющим функцию start/2. Функция start/2 должна затем запустить супервайзор, который часто называется супервайзором верхнего уровня, так как он находится в корне потенциально длинного дерева супервизора. При завершении работы системы все приложения завершают работу своего супервайзора верхнего уровня, который завершает дочерние элементы в обратном порядке их запуска.

Чистое завершение работы активной системы может быть выполнено с помощью вызова System.stop/1. Он завершит работу всех приложений в обратном порядке их запуска. Затем каждое приложение завершит работу своего супервайзора верхнего уровня, если он доступен, который затем завершает работу своих дочерних элементов.

Начиная с Erlang/OTP 19.1, SIGTERM из операционной системы автоматически переведётся в System.stop/0. Erlang/OTP 20 предоставляет пользователю больший контроль над сигналами ОС через функцию :os.set_signal/2.

Обратный вызов модуля приложения

Приложение может запускать и останавливать дерево супервизора при запуске с помощью обратного вызова модуля приложения.

Первый шаг заключается в передаче обратного вызова модуля в определении приложения в файле mix.exs:

def application do
  [mod: {MyApp, []}]
end

Теперь наше приложение требует модуля MyApp для предоставления обратного вызова приложения. Это можно сделать, вызвав use Application в этом модуле и определив обратный вызов start/2, например:

defmodule MyApp do
  use Application

  def start(_type, _args) do
    children = []
    Supervisor.start_link(children, strategy: :one_for_one)
  end
end

start/2 обычно возвращает {:ok, pid} или {:ok, pid, state}, где pid идентифицирует дерево супервизора, а state — состояние приложения. args — второй элемент кортежа, переданного опции :mod.

Аргумент type, передаваемый в start/2, обычно является :normal, за исключением распределённых установок, где настраиваются передача и переключение приложений. Распределённые приложения выходят за рамки этой документации. Для тех, кто интересуется этой темой, пожалуйста, обратитесь к документации OTP:

  • :application модуль
  • Приложения — Принципы проектирования OTP

При завершении работы приложения вызывается его обратный вызов stop/1 после того, как исполняемая среда остановила дерево супервизора. Этот обратный вызов позволяет приложению выполнить любые окончательные операции по очистке. Аргументом является состояние, возвращённое start/2, если оно было, или [] в противном случае. Возвращаемое значение stop/1 игнорируется.

Используя Application, модули получают реализацию по умолчанию для stop/1, которая игнорирует её аргумент и возвращает :ok, но её можно переопределить.

Модули обратного вызова приложения также могут реализовать необязательный обратный вызов prep_stop/1. Если он присутствует, prep_stop/1 вызывается перед завершением работы дерева супервизора. Его аргументом является состояние, возвращённое start/2, если оно было, или [] в противном случае, а его возвращаемое значение передаётся в stop/1.

Приложение без дерева супервизора не определяет обратный вызов модуля приложения в определении приложения в файле mix.exs. Несмотря на отсутствие модуля с обратными вызовами приложения, такими как start/2 и stop/1, приложение можно запустить и остановить так же, как и приложение с деревом супервизора.

Средства разработки

Инструмент сборки Mix также можно использовать для запуска ваших приложений. Например, mix test автоматически запускает зависимости вашего приложения и само приложение перед запуском ваших тестов. mix run --no-halt запускает ваш текущий проект и может использоваться для запуска долгоживущей системы. См. mix help run.

Разработчики также могут использовать инструменты, такие как Distillery, которые создают релизы. Релизы могут упаковать весь ваш исходный код и виртуальную машину Erlang в один каталог. Релизы также дают вам явный контроль над тем, как и в каком порядке запускается каждое приложение. Они также предоставляют более простой механизм для запуска и остановки систем, отладки, ведения журналов и мониторинга системы.

Наконец, Elixir предоставляет инструменты, такие как escripts и архивы, которые представляют собой различные механизмы упаковки вашего приложения. Обычно они используются, когда инструменты должны быть общими для разработчиков, а не в качестве вариантов развертывания. См. mix help archive.build и mix help escript.build для получения дополнительной информации.

Среда приложения

После запуска приложения OTP предоставляет среду приложения, которая может использоваться для настройки приложения.

Предполагая, что вы находитесь внутри проекта Mix, вы можете изменить функцию application/0 в файле mix.exs следующим образом:

def application do
  [env: [hello: :world]]
end

В функции приложения мы можем определить значения среды по умолчанию для нашего приложения. Запустив приложение с помощью iex -S mix, вы можете получить доступ к значению по умолчанию:

Application.get_env(:APP_NAME, :hello)
#=> :world

Приложения и зависимости в проектах Mix обычно настраиваются через файл config/config.exs. Например, тот, кто использует ваше приложение, может настроить ключ :hello следующим образом:

config :APP_NAME, hello: :brand_new_world

Помните, что файлы конфигурации полезны только для настройки статических значений. Например, если вам нужно настраивать приложения на основе среды системы, файловой системы или записей в базе данных, то эти конфигурации лучше разместить во время выполнения. Например, можно динамически настраивать приложения через put_env/3.

Помните, что каждое приложение отвечает за свою среду. Не используйте функции в этом модуле для прямого доступа или изменения среды других приложений (так как это может привести к несогласованным данным в среде приложения).

Резюме

Типы

приложение()
ключ()
тип_запуска()
состояние()
значение()

Функции

app_dir(app)

Получает директорию для приложения.

app_dir(app, path)

Возвращает заданный путь внутри app_dir/1.

delete_env(app, key, opts \\ [])

Удаляет key из заданной app среды.

ensure_all_started(app, type \\ :temporary)

Обеспечивает запуск заданного app и его приложений.

ensure_started(app, type \\ :temporary)

Обеспечивает запуск заданного app.

fetch_env(app, key)

Возвращает значение для key в среде app в кортеже.

fetch_env!(app, key)

Возвращает значение для key в среде app.

format_error(reason)

Форматирует причину ошибки, возвращенную функциями start/2, ensure_started/2, stop/1, load/1 и unload/1, возвращает строку.

get_all_env(app)

Возвращает все пары ключ-значение для app.

get_application(module)

Получает приложение для данного модуля.

get_env(app, key, default \\ nil)

Возвращает значение для key в среде app.

load(app)

Загружает заданное app.

loaded_applications()

Возвращает список с информацией о загруженных приложениях.

put_env(app, key, value, opts \\ [])

Добавляет value в key для данного app.

spec(app)

Возвращает описание для app.

spec(app, key)

Возвращает значение для key в описании app.

start(app, type \\ :temporary)

Запускает заданное app.

started_applications(timeout \\ 5000)

Возвращает список с информацией о приложениях, которые в настоящее время работают.

stop(app)

Останавливает заданное app.

unload(app)

Выгружает заданное app.

Обработчики событий

prep_stop(state)

Вызывается перед остановкой приложения.

start(start_type, start_args)

Вызывается при запуске приложения.

start_phase(phase, start_type, phase_args)

Запускает приложение в синхронных фазах.

stop(state)

Вызывается после остановки приложения.

Типы

app()

app() :: atom()

key()

key() :: atom()

start_type()

start_type() :: :permanent | :transient | :temporary

state()

state() :: term()

value()

value() :: term()

Функции

app_dir(app)

app_dir(app()) :: String.t()

Получает директорию для приложения.

Эта информация возвращается на основе пути к коду. Вот пример:

File.mkdir_p!("foo/ebin")
Code.prepend_path("foo/ebin")
Application.app_dir(:foo)
#=> "foo"

Даже если директория пуста и нет файла .app, она считается директорией приложения на основе имени «foo/ebin». Имя может содержать дефис -, который считается версией приложения, и он удаляется для целей поиска:

File.mkdir_p!("bar-123/ebin")
Code.prepend_path("bar-123/ebin")
Application.app_dir(:bar)
#=> "bar-123"

Для получения более подробной информации о путях к коду, обратитесь к модулю Code в Elixir и к модулю :code в Erlang.

app_dir(app, path)

app_dir(app(), String.t() | [String.t()]) :: String.t()

Возвращает заданный путь внутри app_dir/1.

delete_env(app, key, opts \\ [])

delete_env(app(), key(), timeout: timeout(), persistent: boolean()) :: :ok

Удаляет key из заданной app среды.

См. put_env/4 для описания параметров.

ensure_all_started(app, type \\ :temporary)

ensure_all_started(app(), start_type()) ::
  {:ok, [app()]} | {:error, {app(), term()}}

Обеспечивает запуск заданного app и его приложений.

Аналогично start/2, но также запускает приложения, указанные в :applications файле .app, если они ранее не были запущены.

ensure_started(app, type \\ :temporary)

ensure_started(app(), start_type()) :: :ok | {:error, term()}

Обеспечивает запуск заданного app.

Аналогично start/2, но возвращает :ok если приложение уже запущено. Это полезно в скриптах и при настройке тестов, где тестовые приложения должны быть явно запущены:

:ok = Application.ensure_started(:my_test_dep)

fetch_env(app, key)

fetch_env(app(), key()) :: {:ok, value()} | :error

Возвращает значение для key в среде app в кортеже.

Если параметр конфигурации не существует, функция возвращает :error.

fetch_env!(app, key)

fetch_env!(app(), key()) :: value() | no_return()

Возвращает значение для key в среде app.

Если параметр конфигурации не существует, генерируется исключение ArgumentError.

format_error(reason)

format_error(any()) :: String.t()

Форматирует причину ошибки, возвращенную функциями start/2, ensure_started/2, stop/1, load/1 и unload/1, возвращает строку.

get_all_env(app)

get_all_env(app()) :: [{key(), value()}]

Возвращает все пары ключ-значение для app.

get_application(module)

get_application(atom()) :: atom() | nil

Получает приложение для данного модуля.

Приложение находится путем анализа описания всех загруженных приложений. Возвращает nil если модуль не указан ни в одном описании приложения.

get_env(app, key, default \\ nil)

get_env(app(), key(), value()) :: value()

Возвращает значение для key в среде app.

Если параметр конфигурации не существует, функция возвращает значение default.

load(app)

load(app()) :: :ok | {:error, term()}

Загружает заданное app.

Для загрузки должен существовать файл .app в путях поиска. Все :included_applications также будут загружены.

Загрузка приложения не запускает его и не загружает его модули, но загружает его среду.

loaded_applications()

loaded_applications() :: [tuple()]

Возвращает список с информацией о загруженных приложениях.

put_env(app, key, value, opts \\ [])

put_env(app(), key(), value(), timeout: timeout(), persistent: boolean()) ::
  :ok

Добавляет value в key для данного app.

Параметры

  • :timeout - таймаут изменения (по умолчанию 5_000 миллисекунд)
  • :persistent - сохраняет заданное значение при загрузке и повторной загрузке приложения

Если put_env/4 вызывается до загрузки приложения, значения среды приложения, указанные в файле .app, переопределят ранее заданные.

Параметр persistent может быть установлен в true когда необходимо гарантировать, что параметры, установленные этой функцией, не будут переопределены параметрами, определенными в файле ресурса приложения при загрузке. Это означает, что значения persistent сохранятся после загрузки приложения и также при повторной загрузке приложения.

spec(app)

spec(app()) :: [{key(), value()}] | nil

Возвращает спецификацию для app.

Возвращаются следующие ключи:

  • :description
  • :id
  • :vsn
  • :modules
  • :maxP
  • :maxT
  • :registered
  • :included_applications
  • :applications
  • :mod
  • :start_phases

Обратите внимание, что окружение не возвращается, так как к нему можно получить доступ через fetch_env/2. Возвращает nil если приложение не загружено.

spec(app, key)

spec(app(), key()) :: value() | nil

Возвращает значение для key в спецификации app.

См. spec/1 для поддерживаемых ключей. Если заданный параметр спецификации отсутствует, эта функция вызовет исключение. Возвращает nil если приложение не загружено.

start(app, type \\ :temporary)

start(app(), start_type()) :: :ok | {:error, term()}

Запускает заданное app.

Если app не загружено, приложение сначала загрузится с помощью load/1. Любое включенное приложение, определенное в ключе :included_applications файла .app также будет загружено, но не запущено.

Кроме того, все приложения, перечисленные в ключе :applications должны быть явно запущены до запуска этого приложения. В противном случае возвращается {:error, {:not_started, app}}, где app - имя отсутствующего приложения.

Если вы хотите автоматически загрузить и запустить все зависимости app, см. ensure_all_started/2.

Аргумент type задаёт тип приложения:

  • :permanent - если app завершается, все другие приложения и весь узел также завершаются.

  • :transient - если app завершается с причиной :normal, она сообщается, но другие приложения не завершаются. Если транзиентное приложение завершается аномально, все другие приложения и весь узел также завершаются.

  • :temporary - если app завершается, она сообщается, но другие приложения не завершаются (по умолчанию).

Обратите внимание, что всегда можно явно остановить приложение, вызвав stop/1. Независимо от типа приложения, другие приложения не затронуты.

Обратите также внимание, что тип :transient практически бесполезен, так как когда дерево надзора завершается, причина устанавливается в :shutdown, а не в :normal.

started_applications(timeout \\ 5000)

started_applications(timeout()) :: [tuple()]

Возвращает список с информацией об приложениях, которые в настоящее время выполняются.

stop(app)

stop(app()) :: :ok | {:error, term()}

Останавливает заданное app.

При остановке приложение всё ещё загружено.

unload(app)

unload(app()) :: :ok | {:error, term()}

Выгружает заданное app.

Также выгрузит все :included_applications. Обратите внимание, что функция не очищает модули приложения.

Обработчики

prep_stop(state) (optional)

prep_stop(state()) :: state()

Вызывается перед остановкой приложения.

Эта функция вызывается перед завершением надзорного супервизора верхнего уровня. Она получает состояние, возвращённое start/2, если оно было получено, или [] в противном случае. Возвращаемое значение позднее передаётся в stop/1.

start(start_type, start_args)

start(start_type(), start_args :: term()) ::
  {:ok, pid()} | {:ok, pid(), state()} | {:error, reason :: term()}

Вызывается при запуске приложения.

Эта функция вызывается при запуске приложения с помощью Application.start/2 (и функций над ней, таких как Application.ensure_started/2). Эта функция должна запускать процесс верхнего уровня приложения (который должен быть верхним супервизором дерева надзора приложения, если приложение следует принципам проектирования OTP вокруг надзора).

start_type определяет, как запускается приложение:

  • :normal - используется, если запуск является нормальным запуском или если приложение распределено и запускается на текущем узле из-за переключения с другого узла и ключ спецификации приложения :start_phases равен :undefined.
  • {:takeover, node} - используется, если приложение распределено и запускается на текущем узле из-за переключения на узле node.
  • {:failover, node} - используется, если приложение распределено и запускается на текущем узле из-за переключения на узле node, и ключ спецификации приложения :start_phases не равен :undefined.

start_args - это аргументы, передаваемые приложению в ключе спецификации :mod (например, mod: {MyApp, [:my_args]}).

Эта функция должна либо вернуть {:ok, pid}, либо {:ok, pid, state}, если запуск завершён успешно. pid должен быть PID верхнего супервизора. state может быть произвольным значением, а если оно опущено, оно по умолчанию будет []; если приложение впоследствии остановлено, state передаётся в обратный вызов stop/1 (см. документацию для обратного вызова stop/1 для получения дополнительной информации).

use Application не предоставляет реализацию по умолчанию для обратного вызова start/2.

start_phase(phase, start_type, phase_args) (optional)

start_phase(phase :: term(), start_type(), phase_args :: term()) ::
  :ok | {:error, reason :: term()}

Запустить приложение в синхронных фазах.

Эта функция вызывается после завершения start/2, но перед возвращением Application.start/2. Она будет вызвана один раз для каждой фазы запуска, определённой в спецификации приложения (и любых включённых приложений), в порядке их перечисления.

stop(state)

stop(state()) :: term()

Вызывается после остановки приложения.

Эта функция вызывается после остановки приложения, т.е. после остановки его дерева надзора. Она должна делать обратное тому, что делал обратный вызов start/2, и должна выполнять необходимые операции по очистке. Возвращаемое значение этого обратного вызова игнорируется.

state — это состояние, возвращённое start/2, если оно было получено, или [] в противном случае. Если есть необязательный обратный вызов prep_stop/1, то state — это его возвращаемое значение.

use Application определяет реализацию по умолчанию этой функции, которая ничего не делает и просто возвращает :ok.

© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.6.6/Application.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API