Подтвердить что ты не робот

Управление конфигурацией в приложении Erlang

Мне нужно распространять некоторую статическую конфигурацию через мое приложение. Какова наилучшая практика?

Я вижу три варианта:

  • Вызовите application:get_env напрямую, когда требуется, чтобы модуль получил значение конфигурации.
    • Плюс: проще других.
    • Минус: как протестировать такие модули, не доведя все приложение?
    • Минус: как запустить определенный модуль с другой конфигурацией (если требуется)?
  • Передайте конфигурацию (извлеченную из application:get_env), в прикладные модули во время запуска.
    • Плюс: модули легче тестировать, вы можете запускать их с другой конфигурацией.
    • Минус: много шаблонов. Изменение формата конфигурации требует фиксации нескольких мест.
  • Удерживайте конфигурацию в отдельном процессе настройки.
    • Плюс: более или менее безопасный тип. Легче отслеживать, где используется определенный параметр, и изменять эти места.
    • Минус: нужно запустить процесс настройки перед запуском модулей.
    • Минус: как запустить определенный модуль с другой конфигурацией (если требуется)?
4b9b3361

Ответ 1

Другой подход заключается в преобразовании данных конфигурации в исходный модуль Erlang, который делает данные конфигурации доступными через экспорт. Затем вы можете изменить конфигурацию в любой момент в запущенной системе, просто загрузив новую версию модуля конфигурации.

Ответ 2

Для статической конфигурации в моих собственных проектах мне нравится опция (1). Я покажу вам шаги, которые я предпринимаю для доступа к параметру конфигурации с именем max_widgets в приложении под названием factory.

Сначала мы создадим модуль под названием factory_env, который содержит следующее:

-define(APPLICATION, factory).

get_env(Key, Default) ->
    case application:get_env(?APPLICATION, Key) of
        {ok, Value} -> Value;
        undefined -> Default
    end.

set_env(Key, Value) ->
    application:set_env(?APPLICATION, Key, Value).

Далее, в модуле, который должен читать max_widgets, мы определим макрос следующим образом:

-define(MAX_WIDGETS, factory_env:get_env(max_widgets, 1000)).

В этом подходе есть несколько приятных вещей:

  • Поскольку мы использовали application:set_env/3 и application:get_env/2, нам действительно не нужно запускать приложение factory для прохождения наших тестов.
  • max_widgets получает значение по умолчанию, поэтому наш код будет работать, даже если параметр не определен.
  • Второй модуль может использовать другое значение по умолчанию для max_widgets.

Наконец, когда мы будем готовы к развертыванию, мы поместим файл sys.config в наш каталог priv и загрузим его -config priv/sys.config во время запуска. Это позволяет нам при необходимости изменить параметры конфигурации на основе node. Это чисто отделяет конфигурацию от кода - например, нам не нужно делать еще одну фиксацию, чтобы изменить max_widgets на 500.

Ответ 3

Вы можете использовать процесс (gen_server, возможно?), чтобы сохранить ваши параметры конфигурации в своем состоянии. Он должен открыть интерфейс get/set. Если значение не задано явно, оно должно получить значение по умолчанию.

-export([get/1, set/2]).

...

get(Param) ->
  gen_server:call(?MODULE, {get, Param}).

...

handle_call({get, Param}, _From, State) ->
  case lookup(Param, State#state.params) of
    undefined ->
      application:get_env(...);
    Value ->
      {ok, Value}
  end.

...

Затем вы можете легко макетировать этот модуль в своих тестах. Также будет легко обновить процесс с некоторой новой конфигурацией во время выполнения.

Вы можете использовать сопоставление образцов и кортежи для связывания различных параметров конфигурации с различными модулями:

set({ModuleName, ParamName}, Value) ->
  ...

get({ModuleName, ParamName}) ->
  ...

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

О, я рад, что никто не предлагал параметризованные модули:

Ответ 4

Я бы сделал вариант 1 для статической конфигурации. Вы всегда можете проверить, установив параметры через application:set_env/3,4. Причина, по которой вы хотите сделать это, заключается в том, что ваши тесты приложения должны будут запускать все приложение в любом случае в какое-то время. И возможность установки тестовой конфигурации в этот момент действительно опрятная.

Контроллер приложения работает по умолчанию, поэтому вам не нужно запускать приложение (вам тоже нужно это сделать!)

Наконец, если процесс нуждается в конкретной конфигурации, скажем так в данных конфигурации! Вы можете сохранить любой термин Erlang, в частности, вы можете сохранить термин, который позволяет вам переопределить параметры конфигурации для определенного node.

Для динамической конфигурации вам, вероятно, будет лучше, используя gen_server или используя новейшие функции gproc, которые позволяют хранить такую ​​динамическую конфигурацию.

Ответ 5

Я также видел, что люди используют файл заголовка .hrl(файл заголовка erlang), где вся конфигурация определена и включает его в начале любого файла, который нуждается в конфигурации.

Он обеспечивает очень краткий поиск конфигурации, и вы получаете конфигурацию произвольной сложности.

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

Тем не менее, я на самом деле не проверял, работает ли он так, и я не смог найти окончательную документацию о том, как перезагрузка перезагрузки .hrl и hot code перезагружается, поэтому убедитесь, что вы дважды проверяете это прежде чем вы его используете.