Hatena::Grouperlang

檜山正幸のErlang未確認情報 RSSフィード

 | 

2009-01-15 (木)

helloをちゃんと作る (5) supervisor

| 08:50

スケルトンを埋めてみた。シェルから実験するときは、hello_sup:start() か hello_sup:start_from_shell() を使う。あんまり実験してないので不具合あれば差し替えます。

%% -*- coding: utf-8 -*-

%%% @author M.Hiyama
%%% @doc supervisor for hello application.
-module(hello_sup).

-behaviour(supervisor).

%% API
-export([start_link/0]).

%% Supervisor callbacks
-export([init/1]).
-export([start_from_shell/0, start/0, master_loop/0]).

-define(SUP, ?MODULE).

%% @spec () -> pid()
%% @doc supervisorを起動するが、直後にunlinkする.
%% supervisorプロセスのPIDを返す.
start_from_shell() ->
  {ok, Pid} = start_link(),
  unlink(Pid),
  Pid.

%% @spec () -> pid()
%% @doc ダミーのアプリケーションマスターを使って
%% supervisorを起動する.
start() ->
  spawn(fun () ->
            process_flag(trap_exit, true),
            start_link(),
            master_loop() end).

%% @private
%% @spec () -> ok
%% @doc ダミー・アプリケーションマスターのループ関数.
master_loop() ->
  receive
    {'EXIT', Pid, Why} ->
      io:format("master: Exited ~p Reason:~p~n", [Pid, Why]),
      ok;
    _ ->
      master_loop()
  end.

%%====================================================================
%% API functions
%%====================================================================

%% @spec start_link() -> {ok,Pid} | ignore | {error,Error}
%% where
%%   Pid = pid()
%%   Error = term()
%% @doc Starts the supervisor.
start_link() ->
  supervisor:start_link({local, ?SUP}, % supervisor名(ローカル登録)
                        ?MODULE,       % callbackモジュール名
                        []             % callbackのinit/1に渡される引数
                       ).

%%====================================================================
%% Supervisor callbacks
%%====================================================================

%% @private
%% @spec init(Args::term()) -> Result
%% where
%%  Result = {ok, {{RestartStrategy,MaxR,MaxT}, [ChildSpec]} }
%%         | ignore
%%         | {error, Reason}
%%  RestartStrategy = one_for_all 
%%                  | one_for_one 
%%                  | rest_for_one 
%%                  | simple_one_for_one
%%  MaxR = integer()
%%  MaxT = integer()
%%  ChildSpec = {Id,StartFunc,Restart,Shutdown,Type,Modules}
%%  Id = term()
%%  StartFunc = {M,F,A}
%%  M = atom()
%%  F = atom()
%%  A = [term()]
%%  Restart = permanent | transient | temporary
%%  Shutdown = brutal_kill | integer() | infinity
%%  Type = worker | supervisor
%%  Modules = [Module] | dynamic
%%  Module = atom()

%% @doc Whenever a supervisor is started using 
%% supervisor:start_link/[2,3], this function is called by the new process 
%% to find out about restart strategy, maximum restart frequency and child 
%% specifications.
init(_Args) ->
  % 管理対象(子供達)プロセスの記述
  % 今回は子供は1つだけ、
  % 一般には複数の子供を記述する。
  AChild = {
    hello, % 子供の識別タグ、今回はあまり意味がない
    % 子供の起動情報
    {
      hello_server, % 子供の起動モジュール Mod
      start_link,   % 子供の起動関数 Func
      []            % 子供の起動引数リスト Args
     },
    % リスタート方式
    % * permanent -- 必ず再起動される
    % * transient -- 異常終了したときだけ再起動される
    % * temporary -- 再起動しない
    permanent, % transient, 
    1000, % シャットダウン時間(ミリ秒)
    worker, % プロセスの種別 (wrorker | supervisor)
    [hello_server] % 子供プロセスが使っているコールバックモジュール
   },
  io:format("sup init: Start supervisor (~p)~n", [self()]),  
  {ok,
   {
     {one_for_one, % 再起動ストラテジー
      2, 20 % 失敗判定条件(20秒間に2回までの再起動は許す)
      % 失敗判定条件を上回るクラッシュはツリーを終了する
     }, 
     [AChild] % 子供のリスト(今回は1つだけ)
    }
  }.
%%====================================================================
%% Internal functions
%%====================================================================

%% The End

 |