supervisor

仕事が落ち着いたので、erlang 勉強再開。
id:cooldaemon:20070625 と id:cooldaemon:20070630 で作った server を supervisor tree に入れてみた。

-module(sup).
-behaviour(supervisor).

-export([start_link/1, stop/0]).
-export([init/1, worker_spec/2]).

start_link(Code) ->
  supervisor:start_link({local, ?MODULE}, ?MODULE, [Code]).

stop() ->
  case whereis(?MODULE) of
    Pid when pid(Pid) ->
      exit(Pid, shutdown),
      ok;
    _ ->
      not_started
  end.

init(Code) ->
  Flags = {one_for_one, 0, 1},
  Children = [
    worker_spec(counter, []),
    worker_spec(code_lock, [Code])
  ],
  {ok, {Flags, Children}}.

worker_spec(WokerModule, Args) ->
  StartFunc = {WokerModule, start_link, Args},
  {WokerModule, StartFunc, permanent, brutal_kill, worker, [WokerModule]}.

sup:start_link("abcd"). で counter と code_lock が起動し、sup:stop(). で全てが停止する。

proc_lib で echoserver を書き直した

gen_server、supervisor、proc_lib の三つを押さえれば、httpd.erl の起動と停止の動作を理解する事が可能。
って事で、以前 みかログ: Erlang で echo server こちらで添削して頂いた id:cooldaemon:20070614 を proc_lib で書き直してみた。

-module(echoserver3).
-export([start_link/0, stop/0]).
-export([init/1, accept/1, handle_connection/1, recv_loop/1]).

start_link() ->
  proc_lib:start_link(?MODULE, init, [self()]).

stop() ->
  case whereis(?MODULE) of
    Pid when pid(Pid) ->
      exit(Pid, shutdown),
      ok;
    _ ->
      not_started
  end.

init(Parent) ->
  register(?MODULE, self()),

  case gen_tcp:listen(
    8080, [{active, false}, binary, {packet, line}, {reuseaddr, true}]
  ) of
    {ok, ListenSocket} ->
      proc_lib:init_ack(Parent, {ok, self()}),
      accept(ListenSocket);
    {error, Reason} ->
      proc_lib:init_ack(Parent, {error, Reason}),
      error
  end.

accept(ListenSocket) ->
    {ok, Socket} = gen_tcp:accept(ListenSocket),
    spawn_link(?MODULE, handle_connection, [Socket]),
    accept(ListenSocket).

handle_connection(Socket) ->
    gen_tcp:send(Socket, <<"hello\r\n">>),
    recv_loop(Socket).

recv_loop(Socket) ->
    case gen_tcp:recv(Socket, 0) of
        {ok, B} ->
            case B of
                <<"bye\r\n">> ->
                    gen_tcp:send(Socket, <<"cya\r\n">>),
                    gen_tcp:close(Socket);
                Other ->
                    gen_tcp:send(Socket, Other),
                    recv_loop(Socket)
            end;
        {error, closed} ->
            ok
    end.

gen_server 等の behaviour は、proc_lib を元に作られている。よって、特にステータス管理を行わないのであれば、proc_lib で十分。
処理をブロックするなら gen_server を選択できないので proc_lib を使うしかない。

添削・突っ込み 大歓迎。