erlang otp童工
我试图让一个OTP主管启动将会(最终)连接到远程服务器的童工。 我使用钢筋来创建一个模板测试应用程序,我试图让主管在模块'foo'中激发函数'hi'。 它编译好并运行:
Eshell V5.8.5 (abort with ^G)
1> test_app:start(1,1).
{ok,<0.34.0>}
但是当我尝试启动工作人员时,会出现梨形状,并显示以下错误消息:
2> test_sup:start_foo().
{error,{badarg,{foo,{foo,start_link,[]},
permanent,5000,worker,
[foo]}}}
这个问题似乎与这个问题类似,但不一样:Erlang - 从supervisor模块启动一个孩子
有任何想法吗?
test_app.erl
-module(test_app).
-behaviour(application).net
-export([start/2, stop/1]).
start(_StartType, _StartArgs) ->
test_sup:start_link().
stop(_State) ->
ok.
Test_sup.erl:
-module(test_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1, start_foo/0]).
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
{ok, { {one_for_one, 5, 10}, []} }.
start_foo()->
supervisor:check_childspecs(?CHILD(foo, worker)),
supervisor:start_child(?MODULE, ?CHILD(foo, permanent)).
foo.erl:
-module(foo).
-export([hi/0]).
hi()->
io:format("worker ~n").
我认为罗伯特的回答是不完整的,在由工作人员取代永久性工作人员之后,您仍然有一个由supervisor:check_childspecs(?CHILD(foo, worker)),
返回的错误supervisor:check_childspecs(?CHILD(foo, worker)),
,我不知道为什么。
[编辑]
吟游诗人arg的问题来自... badarg:o)
check_childspecs扩展了child_specs的列表,正确的语法是supervisor:check_childspecs([?CHILD(foo, worker)]),
然后它工作正常。 下面的代码被更新。
[编辑结束]
但是你也会得到一个错误,因为主管将尝试启动foo模块中不存在的函数foo:start_link。 下面的代码打印一个错误,但似乎正常工作。
-module(foo).
-export([hi/0,start_link/0,loop/0]).
start_link() ->
{ok,spawn_link(?MODULE,loop,[])}.
hi()->
io:format("worker ~n").
loop() ->
receive
_ -> ok
end.
-module(test_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1, start_foo/0]).
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
{ok, { {one_for_one, 5, 10}, []} }.
start_foo()->
io:format("~p~n",[supervisor:check_childspecs([?CHILD(foo, worker)])]),
supervisor:start_child(?MODULE, ?CHILD(foo, worker)).
[编辑]
回答大卫的评论
在我的代码中, loop/0
根本不循环,在接收块上,进程等待任何消息,并且只要收到一个消息,进程就会返回值ok。 所以只要工作流程没有收到任何信息,它就会继续存在,当你和主管进行一些测试时,这很好:o)。
相反,hi / 0函数只是在控制台上打印'worker'并结束。 由于主管的重启策略是one_for_one,最大重启次数是5次,子进程是永久的,主管会尝试启动hi进程5次,在控制台上打印五次'worker',然后它会放弃并用错误消息** exception error: shutdown
终止本身** exception error: shutdown
一般来说,您应该选择permanent
结束进程(例如应用程序的主服务器)。 对于通常在他们完成工作后就会死亡的流程,您应该使用temporary
流程。 我从来没有使用transient
但我读到它应该用于在死前必须完成任务的过程。
当你尝试用宏调用宏来启动孩子时,你使用宏调用?CHILD(foo, worker)
来检查childspec ?CHILD(foo, permanent)
。 CHILD
宏的第二个参数是过程类型,它应该是worker
或supervisor
。 所以第一个宏调用是正确的。 permanent
值是重启类型的值,您已经设置为permanent
,因此第二次调用是错误的,并且您会收到badarg
错误。
注意:库函数badarg
生成badarg
错误,而不仅仅是内置函数。 为什么它是badarg并不总是显而易见的。