Erlang,覆盖环境

Via*_*lev 2 erlang config

我有一个带有一些应用程序的erlang节点.我想让我的应用程序从某个集中式服务器(例如hiera server)获取其环境变量.有没有办法从.app文件覆盖环境变量,用从某个地方获得的自定义变量替换它?当然,我不想对我的应用程序代码进行任何更改.

Sou*_*lls 5

如果您想完全避免更改应用程序的代码,最好的办法是使用外部配置文件并从集中式服务器复制到每个"本地"服务器.如果在sys.config中的应用程序列表末尾指定文件路径(假设您正在使用版本),则BEAM VM还将加载此文件作为附加配置.

使用此方法,您可以在/etc/my_service/extended.config之类的位置创建文件,并使用某种服务或其他服务自动更新.Puppet是一个可以为你做这个部分的工具的例子; 看起来像Hiera(我不熟悉)会是另一个.

为清楚起见,使用此方法,您的sys.config文件应如下所示:

[
    {my_app1, [
            {my_param1, 1},
            {my_param2, "string"}
        ]},
    {my_app2, [
            ...
        ]},
    "/etc/my_service/extended.config"
].
Run Code Online (Sandbox Code Playgroud)

但是,这种方法有一些显着的局限性,即配置文件只加载一次,如果要在服务运行时更改它,则必须重新启动BEAM VM.如果您生成Erlang版本(因此sys.config),它也最有效.

如果您没有使用Erlang版本且没有sys.config文件,您仍然可以使用-config命令行参数指定配置文件erl

最好的方法IMO要求您对应用程序进行一些小的修改.我建议将参数存储在分布式mnesia表(或任何其他数据库中,实际上,只要您可以轻松查询它).随后,application:get_env/2,3通过调用您定义的函数来替换您的调用,该函数会在回退之前检查您正在存储设置的数据库application:get_env/2,3.

例如:

-record(setting, {key, value}).
get_setting(App, Key) ->
    get_setting(App, Key, undefined).

get_setting(App, Key, Default) ->
    case mnesia:dirty_read(settings, {App, Key}) of
        [] ->
            application:get_env(App, Key, Default);
        [_ = #setting{value = Value}] ->
            Value
    end.
Run Code Online (Sandbox Code Playgroud)