Erlang,覆盖环境

Erlang,覆盖环境,erlang,config,Erlang,Config,我有一个带有一些应用程序的erlang节点。我想让我的应用程序从某个集中式服务器(例如,hiera服务器)获取环境变量。有没有办法覆盖.app文件中的环境变量,将其替换为从特定位置获取的自定义变量? 当然,我不想对我的应用程序代码进行任何更改。如果您想完全避免更改应用程序的代码,最好使用外部配置文件,并将其从集中式服务器复制到每个“本地”服务器。如果您在sys.config中的应用程序列表末尾指定了一个文件路径(假设您使用的是版本),则BEAM VM也会将此文件作为附加配置加载 使用此功能,您可

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

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

使用此功能,您可以在/etc/my_service/extended.config这样的位置创建一个文件,并使用某个或另一个服务自动更新该文件。木偶是一个可以为你做这件事的工具的例子;看起来希拉(我不熟悉)将是另一个

为了清楚起见,使用这种方法,sys.config文件应该如下所示:

[
    {my_app1, [
            {my_param1, 1},
            {my_param2, "string"}
        ]},
    {my_app2, [
            ...
        ]},
    "/etc/my_service/extended.config"
].
但是,这种方法有一些明显的局限性,即配置文件只加载一次,如果您想在服务运行时对其进行更改,则必须重新启动BEAM VM。如果您正在生成一个Erlang发行版(因此是sys.config),那么它也最有效

如果您没有使用Erlang版本并且没有sys.config文件,那么仍然可以使用
-config
命令行参数和
erl

最好的方法是IMO,要求您对应用程序进行一些小的修改。我建议将您的参数存储在分布式mnesia表中(或者任何其他数据库,只要您可以轻松查询)。随后,将
应用程序:get_env/2,3
调用替换为对您定义的函数的调用,该函数在返回到
应用程序: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.

“不想做任何更改”是否会自动排除使用“set_env/3”?我认为
set_env/3
是合适的,但我正在寻找一种方法,不在我的应用程序中保留任何此类逻辑。想一想,使用某些应用程序是合适的,这些应用程序将在其他应用程序之前加载,并设置任何其他应用程序。
application:get_env/1,2,3
很容易成为高度并发场景中的瓶颈,因此最好只在gen_server init阶段执行此操作,然后将配置置于其状态。这就是为什么要在应用程序启动后设置env,就必须编写自定义逻辑来处理配置更新。这是一个奇怪的盲点,大多数配置语言都允许在文件中内联env变量,从而允许在每台机器或每台代理上设置这些变量。在docker内部,chicagoboss遇到了一个类似的问题(用于映射链接资源),这让我大吃一惊。现在看起来像是一个复制和sed解决方案。在这上面花了太多时间。如果我更喜欢冒险,我会把逻辑放在boss的rebar_插件挂钩中。是的,谢谢你这么详细的回答,我认为,最适合我的是从hiera生成配置文件,并在BEAM启动之前将此配置复制到每个本地服务器。