我需要通过我的应用程序分发某种静态配置。这样做的最佳做法是什么?
我看到三个选项:
application:get_env
。
application:get_env
检索)传递给应用程序模块。
答案 0 :(得分:12)
另一种方法是将配置数据转换为Erlang源模块,通过导出使配置数据可用。然后,您只需加载新版本的配置模块,即可在正在运行的系统中随时更改配置。
答案 1 :(得分:10)
对于我自己项目中的静态配置,我喜欢选项(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
的其他默认值。最后,当我们准备好部署时,我们会在priv
目录中放置一个sys.config文件,并在启动期间使用-config priv/sys.config
加载它。这允许我们根据需要在每个节点上更改配置参数。这样可以将配置与代码完全分开 - 例如我们不需要再提交一次,以便将max_widgets
更改为500。
答案 2 :(得分:7)
您可以使用进程(可能是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}) ->
...
将流程置于监督树下,因此在所有其他需要配置的流程之前启动。
哦,我很高兴到目前为止没有人建议parametrized modules:)
答案 3 :(得分:3)
我会为静态配置执行选项1。您始终可以通过application:set_env/3,4
设置选项进行测试。您希望这样做的原因是您的应用程序测试需要在某个时间运行整个应用程序。此时设置测试特定配置的能力非常好。
应用程序控制器默认运行,因此您不需要按应用程序方式运行(无论如何也需要这样做!)
最后,如果进程需要特定配置,请在配置数据中这样说!您可以存储任何Erlang项,特别是您可以存储一个术语,使您能够覆盖特定节点的配置参数。
对于动态配置,您可能最好使用gen_server
或使用最新的gproc
功能来存储此类动态配置。
答案 4 :(得分:0)
我还看到人们使用.hrl(erlang头文件),其中定义了所有配置,并将其包含在需要配置的任何文件的开头。
它使得配置查找非常简洁,并且您可以获得任意复杂性的配置。
我相信你也可以通过执行模块的热代码重新加载来重新加载配置。缺点是如果您在多个模块中使用配置并仅重新加载其中一个模块,则只有一个模块将更新其配置。
然而,我还没有真正检查过它是否有效,而且我无法找到关于.hrl和热代码重新加载如何交互的明确文档,所以请务必在实际使用之前仔细检查一下。