应用程序启动时将一些参数传递给主管 init 函数

mel*_*kes 2 erlang erlang-otp

我想将一些参数传递给supervisor:init/1函数,并且希望应用程序的界面如下所示:

redis_pool:start() % start all instances
redis_pool:start(Names) % start only given instances
Run Code Online (Sandbox Code Playgroud)

这是应用程序:

-module(redis_pool).
-behaviour(application).

...

start() -> % start without params
    application:ensure_started(?APP_NAME, transient).

start(Names) -> % start with some params
    % I want to pass Names to supervisor init function
    % in order to do that I have to bypass application:ensure_started
    % which is not GOOD :(
    application:load(?APP_NAME),
    case start(normal, [Names]) of
        {ok, _Pid} -> ok;
        {error, {already_started, _Pid}} -> ok
    end.

start(_StartType, StartArgs) ->
    redis_pool_sup:start_link(StartArgs).
Run Code Online (Sandbox Code Playgroud)

这是主管:

init([]) ->
    {ok, Config} = get_config(),
    Names = proplists:get_keys(Config),
    init([Names]);
init([Names]) ->
    {ok, Config} = get_config(),
    PoolSpecs = lists:map(fun(Name) ->
        PoolName = pool_utils:name_for(Name),
        {[Host, Port, Db], PoolSize} = proplists:get_value(Name, Config),
        PoolArgs = [{name, {local, PoolName}},
                {worker_module, eredis},
                {size, PoolSize},
                {max_overflow, 0}],
        poolboy:child_spec(PoolName, PoolArgs, [Host, Port, Db])
    end, Names),
    {ok, {{one_for_one, 10000, 1}, PoolSpecs}}.
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,当前的实现很丑陋并且可能存在错误。问题是我如何传递一些参数并启动应用程序和主管(使用给予的参数start/1)?

一种选择是启动应用程序并分两个单独的阶段运行 Redis 池。

redis_pool:start(),
redis_pool:run([] | Names).
Run Code Online (Sandbox Code Playgroud)

但是,如果我想在应用程序启动时运行主管子级(redis 池)怎么办?

谢谢。

Rog*_*mbe 5

应用程序回调Module:start/2不是为了启动应用程序而调用的 API。当应用程序启动时调用它application:start/1,2。这意味着重载它来提供不同的参数可能是错误的做法。

特别是,如果有人将您的应用程序添加为他们的应用程序的依赖项(在文件中),application:start将直接调用。foo.app此时,他们无法控制参数,因为它们来自您的 .app文件{mod, {Mod, Args}}

一些可能的解决方案:

应用程序配置文件

要求参数位于应用程序配置文件中;您可以使用 检索它们application:get_env/2,3

不要启动主管

这意味着以下两件事之一:成为图书馆应用程序({mod, Mod}.app文件中删除该术语)——您不需要application行为;或者启动一个什么也不做的虚拟主管。

然后,当有人想要使用您的库时,他们可以调用 API 来创建池监督程序,并将其移植到他们的监督树中。这就是 的poolboy作用poolboy:child_spec

或者,您的应用程序级主管可以是普通主管,默认情况下没有子级,并且您可以提供一个 API 来通过supervisor:start_child. 这(或多或少)就是这样cowboy的。