1

OTP スーパーバイザーに、(最終的に) リモート サーバーに接続する子ワーカーを開始させようとしています。Rebar を使用してテンプレート テスト アプリケーションを作成し、スーパーバイザーにモジュール '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 - Starting a child from Supervisor Module

何か案は?

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").
4

2 に答える 2

0

ロバートの答えは不完全だと思います.permanentを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」を 5 回出力してからあきらめます。エラーメッセージで終了します** exception error: shutdown

permanent一般に、終了しないプロセス (アプリケーションのメイン サーバーなど) を選択する必要があります。通常、ジョブが完了するとすぐに終了するプロセスの場合は、 を使用する必要がありますtemporary。使用transientしたことはありませんが、死ぬ前にタスクを完了する必要があるプロセスに使用する必要があることを読みました.

于 2013-10-23T04:16:56.067 に答える