2016-11-24 9 views
5

私は構築している分散アプリケーションでerlangのOTPスーパーバイザを使用したいと思います。しかし、私は、この種のスーパーバイザーがリモートノード上で実行されているプロセスをどのように監視できるかを理解することができません。 erlangのstart_link関数とは異なり、start_childには、子が生成されるノードを指定するためのパラメータはありません。OTPスーパーバイザはリモートノード上のプロセスを監視できますか?

OTPスーパーバイザがリモートの子を監視することは可能ですか?そうでない場合は、どのようにしてerlangでこれを達成できますか?

+1

私は、各ノードにスーパーバイザを置くことをお勧めします。 – Dogbert

+0

@Dogbert確かに。実際にはスーパーバイザーだけでなく、通常はどのようなシステムでも完全なレプリカが配布されるため、作業要求はコードを大幅に変更することなくノード間で行うことができます。 – zxq9

答えて

3

supervisor:start_child/2はノード間で使用できます。

あなたの混乱の理由は、実行のコンテキストについて混乱しているだけです(これは、時にはまれにあることがあります)。任意のOTPの産卵に関与三つのプロセスがあります。

  • リクエスタ
  • スーパーバイザ
  • 生成されたプロセス

リクエスタのコンテキストがsupervisor:start_child/2が呼び出されるものであるが - ではないスーパーバイザ自体のコンテキスト。

定義されており、スーパーバイザモジュールからエクスポートされる可能性があります
do_some_crashable_work(Data) -> 
    supervisor:start_child(sooper_dooper_sup, [Data]). 

は、発明の方法の「管理者」の並べ替えの内部で定義されて:あなたは、通常supervisor:spawn_child/2への呼び出しをラップ機能をエクスポートすることにより、スーパーバイザー・インターフェースを提供します"service manager/supervisor/workers" idiomなどです。しかし、いずれの場合も、監督者以外のプロセスがこの呼び出しを行っています。

supervisor:start_child/2のErlangドキュメントをもう一度見てください(here、およびan R19.1 doc mirror)。何らかの理由でerlang.orgに苦労することがあります。タイプsup_ref()は登録名、pid(){global, Name}または{Name, Node}とすることができます。リクエスタは、pid(),{global, Name}または{Name, Node}タプルを使用してコールするときに、他のノード上のスーパーバイザを呼び出す任意のノード上にある可能性があります。

スーパーバイザーはランダムにキックオフしません。 child_spec()があります。スペックは、新しいプロセスを開始するために何を呼び出すべきか監督者に指示します。子モジュールへの最初の呼び出しは、のスーパバイザコンテキストでとなり、カスタム関数です。我々は通常start_link/Nのような名前をつけていますが、起動させる特定のノードを宣言することを含め、スタートアップの一環として何でもできます。以下のようなものの子仕様で

%% Usually defined in the requestor or supervisor module 
do_some_crashable_work(SupNode, WorkerNode, Data) -> 
    supervisor:start_child({sooper_dooper_sup, SupNode}, [WorkerNode, Data]). 

:だから今、私たちはこのような何かをする羽目になる

%% Usually in the supervisor code 
SooperWorker = {sooper_worker, 
       {sooper_worker, start_link, []}, 
       temporary, 
       brutal_kill, 
       worker, 
       [sooper_worker]}, 

最初の呼び出しはsooper_worker:start_link/2になることを示している:

%% The exported start_link function in the worker module 
%% Called in the context of the supervisor 
start_link(Node, Data) -> 
    Pid = proc_lib:spawn_link(Node, ?MODULE, init, [self(), Data]). 

%% The first thing the newly spawned process will execute 
%% in its own context, assuming here it is going to be a gen_server. 
init(Parent, Data) -> 
    Debug = sys:debug_options([]), 
    {ok, State} = initialize_some_state(Data) 
    gen_server:enter_loop(Parent, Debug, State). 

あなたはproc_libを使って何が起こっているのかが不思議に思うかもしれません。マルチノードシステム内のどこからでも、マルチノードシステム内の他の場所で生成を開始するためには、の可能性がありますが、これは非常に便利な方法ではありません。 gen_*ビヘイビアー、さらにはproc_lib:start_link/Nには、新しいプロセスを生成するノードを宣言するメソッドがありません。

あなたが理想的に望むのは、自分自身を初期化し、実行中にクラスタに参加する方法を知っているノードです。あなたのシステムが提供するサービスは、通常、クラスタ内の他のノードで最もよくレプリケートされます。ノードを選ぶ方法を書くだけでよいので、スタートアップのビジネスを完全にノードローカルにすることができますすべての場合。この場合、あなたの通常のマネージャ/スーパバイザ/ワーカーコードは何も変更する必要はありません。ちょうど起こります。リクエスタのPIDは、そのPIDが別のノードにあっても問題ありません。結果を返す必要があります。別の言い方をすれば

が、私たちは本当に任意のノード上の労働者を起動したくない、私たちが本当にやりたいことは、より高いレベルといくつかの作業が別のノードによってを成し遂げる要求にステップアップし、本当に気にしませんどのように起こるかについて。覚えておいてください。{M,F,A}呼び出しに基づいて特定の機能を起動するには、呼び出すノードがターゲットモジュールと機能にアクセスする必要があります。コードのコピーが既に存在する場合、呼び出し元のノードと重複しません。

うまくいけば、この回答は混乱した以上に説明されました。

関連する問題