Erlang 当应用程序启动时,将一些参数传递给supervisor init函数

Erlang 当应用程序启动时,将一些参数传递给supervisor init函数,erlang,otp,Erlang,Otp,我想把一些参数传递给supervisor:init/1函数,希望应用程序的接口是这样的: redis_pool:start() % start all instances redis_pool:start(Names) % start only given instances 以下是应用程序: -module(redis_pool). -behaviour(application). ... start() -> % start without params applicat

我想把一些参数传递给supervisor:init/1函数,希望应用程序的接口是这样的:

redis_pool:start() % start all instances
redis_pool:start(Names) % start only given instances
以下是应用程序:

-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).
这是主管:

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}}.
正如您所看到的,当前的实现是丑陋的,并且可能有缺陷。问题是我如何传递一些参数,并使用指定给start/1的参数启动应用程序和主管

一个选项是启动应用程序并分两个阶段运行redis池

redis_pool:start(),
redis_pool:run([] | Names).
但如果我想在应用程序启动时运行redis池怎么办


谢谢。

您可以将AppDescr参数中的参数传递给application:load/1,尽管它已经是一个非常大的元组了。。。作为{mod,{Module,StartArgs}}根据文档根据中的文档,我不记得自己是这样做的,曾经:

在不了解要启动的应用程序的内部结构的情况下,很难说哪种方式是最好的,但一种常见的方法是启动应用程序,然后向它发送一条包含您希望它知道的数据的消息

您可以接收消息表单,告诉应用程序执行一个配置断言过程,这样您在启动时发送的相同消息也与您在运行时发送以重新配置它的消息相同。我发现这比在启动时抛出论点更有用


在任何情况下,通常最好先考虑开始做某事,然后让它为您做些事情,而不是尝试在init参数中告诉它一切。这可以很简单,只要让它启动并等待一些消息,这些消息会告诉侦听器然后按照您在这里尝试的方式启动管理器-将一步从他在回答中提到的应用程序包含问题RL中分离出来。

您可以将AppDescr参数中的参数传递给application:load/1,尽管这是一个非常大的问题元组已经。。。作为{mod,{Module,StartArgs}}根据文档根据中的文档,我不记得自己是这样做的,曾经:

在不了解要启动的应用程序的内部结构的情况下,很难说哪种方式是最好的,但一种常见的方法是启动应用程序,然后向它发送一条包含您希望它知道的数据的消息

您可以接收消息表单,告诉应用程序执行一个配置断言过程,这样您在启动时发送的相同消息也与您在运行时发送以重新配置它的消息相同。我发现这比在启动时抛出论点更有用

在任何情况下,通常最好先考虑开始做某事,然后让它为您做些事情,而不是尝试在init参数中告诉它一切。这可以简单到让它启动并等待一些消息,这些消息将告诉侦听器然后按照您在这里尝试的方式启动管理器-将一个步骤与他在回答中提到的应用程序包含问题RL隔离。

应用程序回调模块:start/2不是启动应用程序所需调用的API。当应用程序由application:start/1,2启动时调用它。这意味着重载它以提供不同的参数可能是错误的

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

一些可能的解决办法:

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

不要任命一个主管 这意味着两件事之一:成为一个库应用程序,从你的.app文件中删除{mod,mod}项——你不需要应用程序行为;或者启动一个什么都不做的虚拟主管

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

或者,您的应用程序级主管可以是普通主管,默认情况下没有子级,并且您可以通过supervisor:start\u child提供一个API来启动该应用程序的子级。这或多或少就是cowboy所做的。

应用程序回调模块:start/2不是启动应用程序所需调用的API。当应用程序由application:start/1,2启动时调用它。这意味着重载它以提供不同的参数可能是错误的

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

一些可能的解决办法:

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

不要任命一个主管 这意味着两件事之一:成为一个库应用程序,从你的.app文件中删除{mod,mod}项——你不需要应用程序行为;或者启动一个什么都不做的虚拟主管

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


或者,您的应用程序级主管可以是普通主管,默认情况下没有子级,并且您可以通过supervisor:start\u child提供一个API来启动该应用程序的子级。这或多或少就是牛仔所做的。

谢谢罗杰的详细解释!对于那些阅读本文的人,我最终启动了一个有0个孩子的supervisor,并拥有runNames和run_all函数,这将孩子添加到supervisor中。感谢罗杰的详细解释!对于那些阅读本文的人,我最终启动了一个有0个子项的supervisor,并使用runNames和run_all函数,将子项添加到supervisor中。
application:load({application, some_app, {mod, {Module, [Stuff]}}})