1.05.2014

Getting Started with Erlang pt.6

Erlang をはじめよう その6

 

前回 - mog project: Getting Started with Erlang pt.5 の続き

CHAPTER 11: Getting Started with OTP

いよいよ OTP の章に入る。

OTPとは Open Telecom Platform の略。
分散並列処理のためのライブラリ群と耐障害性の高いアプリケーションサーバ機能を持った
フレームワークの名称である。

Open Telecom Platform - Wikipedia, the free encyclopedia

この OTP の機能を活用することこそ、Erlang を使う最大の目的である。

 

モジュールをサービスとして実行する

-define はマクロの定義、?MODULE は組み込みマクロ。

-module(shop).
-behaviour(gen_server).
-export([start_link/0]). % convenience call for startup
-export([init/1,
         handle_call/3,
         handle_cast/2,
         handle_info/2,
         terminate/2,
         code_change/3]). % gen_server calls
-define(SERVER, ?MODULE). % macro that just defines this module as server
-record(state, {count}). % simple counter state

%%% convenience method for startup
start_link() ->
        gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

%%% gen_server callbacks
init([]) ->
        {ok, #state{count=0}}.

handle_call(_Request, _From, State) ->
        Distance = _Request,
        Reply = {ok, buy(Distance)},
        NewState=#state{ count = State#state.count+1 },
        {reply, Reply, NewState}.

handle_cast(_Msg, State) ->
        io:format("So far, calculated ~w prices.~n", [State#state.count]),
        {noreply, State}.

handle_info(_Info, State) ->
        {noreply, State}.

terminate(_Reason, _State) ->
        ok.

code_change(_OldVsn, State, _Extra) ->
        {ok, State}.

%%% Internal functions

buy(Number) -> 100 * Number.

実行

> c(shop)
> shop:start_link().
> gen_server:call(shop, 3).
> gen_server:call(shop, 5).
> gen_server:cast(shop, {}).
> gen_server:call(shop, 7).
> gen_server:cast(shop, {}).

サーバ実行中にモジュールを書き換えることもできる。
例えば、shop.erl の最終行を以下のように書き換える。

buy(Number) -> 105 * Number.

先ほどのコンソールで引き続き。

> c(shop).
> gen_server:call(shop, 7).
> gen_server:cast(shop, {}).

ただし、処理中にエラーが発生するとサーバは停止してしまう。

> gen_server:call(shop, apple).
> gen_server:call(shop, 7).

 

スーパーバイザーの実行
-module(shop_sup).
-behaviour(supervisor).
-export([start_link/0]). % convenience call for startup
-export([init/1]). % supervisor calls
-define(SERVER, ?MODULE). % macro that just defines this module as server


%%% convenience method for startup
start_link() ->
        supervisor:start_link({local, ?SERVER}, ?MODULE, []).

%%% supervisor callback
init([]) ->
        RestartStrategy = one_for_one,
        MaxRestarts = 1, % one restart every
        MaxSecondsBetweenRestarts = 5, % five seconds

        SupFlags = {RestartStrategy, MaxRestarts, MaxSecondsBetweenRestarts},

        Restart = permanent, % or temporary, or transient
        Shutdown = 2000, % milliseconds, could be infinity or brutal_kill
        Type = worker, % could also be supervisor

        Shop = {shop, {shop, start_link, []},
                          Restart, Shutdown, Type, [shop]},

        {ok, {SupFlags, [Shop]}}.


%%% Internal functions (none here)

実行

> c(shop_sup).
> {ok, Pid} = shop_sup:start_link().
> unlink(Pid).
> gen_server:call(shop, 3).
> whereis(shop).
> gen_server:call(shop, apple).    % error
> whereis(shop).
> gen_server:call(shop, 5).

start_link を行うとシェル自身がスーパーバイザーになってしまうので、
サーバを起動し続けるためには unlink を行う必要がある。

別の方法としては、gen_server:call の呼び出しを catch で囲むアプローチもある。

 

アプリケーションとしてパッケージングする

アプリケーション リソースファイル

{application,shop,
[{description,"Shopping some fruits"},
{vsn,"0.0.1"},
{modules,[shop, shop_sup]},
{applications,[kernel,stdlib]},
{mod,{shop_app,[]}}]}.

アプリケーション モジュール

-module(shop_app).
-behaviour(application).
-export([start/2, stop/1]).

start(_Type, _StartArgs) ->
  shop_sup:start_link().

stop(_State) ->
  ok.

実行

> c(shop_app).
> application:load(shop).
> application:loaded_applications().
> application:start(shop, 3).
> application:start(shop).
> gen_server:call(shop, 3).
> whereis(shop).
> gen_server:call(shop, apple).
> whereis(shop).
> gen_server:call(shop, 5).

カレントディレクトリ以外の場所にリソースがある場合には
code:add_path("path/to/the/directory").
が必要。

 

CHAPTER 12: Next Steps Through Erlang

最終章。次のステップは?

 

 

 

References

 

Related Posts

0 件のコメント:

コメントを投稿