Персональные инструменты
Вы здесь: Главная Блог Yet Another Sum-it-up on the Erlang/OTP basics.

Yet Another Sum-it-up on the Erlang/OTP basics.

Автор: Фёдор Сахаров at 2009-11-28 22:02 |

Basics of the Open Telecom Platform.

Кроме непосредственно языка Erlang есть платформа Open Telecom Platform (OTP). Об основных принципах разработки с использованием OTP можно прочесть здесь.

Если коротоко, то OTP – это набор приципов структурирования кода с использованием деревьев контроля, в которые входят супервизоры и рабочие. В корне дерева контроля находится один большой и главный супервизор, который контролирует ход выполнения своих потомков, которые, в свою очередь, могут быть либо супервизорами, либо работниками (как правило — листья дерева контроля). Поведение первых и, зачастую, поведение вторых описывают с использованием общих паттернов. Идея таких паттернов заключается в разнесении кода модуля на две части. Одна из этих частей содержит код общий для всех модулей с таким поведением, другая — код, специфичный для данного модуля. Специфичная для данного приложения часть кода содержит реализацию коллбеков. Множество коллбеков является строго определенным для каждого типа поведений.

Рассмотрим данную концепцию на примере поведения Generic Server и Supervisor.

Маны говорят нам, какие функции в модуле паттерна вызывают какие функции из модуля коллбеков.

gen_server module            Callback module
-----------------            ---------------
gen_server:start_link -----> Module:init/1
gen_server:call
gen_server:multi_call -----> Module:handle_call/3
gen_server:cast
gen_server:abcast     -----> Module:handle_cast/2
-                     -----> Module:handle_info/2
-                     -----> Module:terminate/2
-                     -----> Module:code_change/3

Функция

start_link(Module, Args, Options) -> Result

Аргумент Module — имя модуля, содержащего коллбеки.
Args — список аргументов, который будет передан в функцию Module:init/1.

порождает процесс с поведением gen_server. Данный процесс становится частью дерева контроля. Далее он вызывает функцию инициализации из модуля коллбеков (Module:init/1).

Серверу возможно посылать синхронные и асинхронные запросы. Синхронные запросы осуществляются с помощью вызова функции gen_server:call(ServerRef, Request). ServerRef идентифицирует сервер, которому посылается этот запрос. Request — любая структура языка Erlang, которая будет обработана коллбеком handle_call данного сервера.

Supervisor.
Процесс супервизора создается при вызове функции start_link() и становится частью дерева контроля. Рассмотрим вариант этой функции start_link(Module, Args). Module — имя модуля, содержащего набор коллбеков супервизора. Args — список аргументов, которые будут переданы функции Module:init/1. Данная функций должна возвращать набор {ok, {{RestartStrategy, MaxR, MaxT},[ChildSpec]}}, где RestartStrategy — стратегия перезапуска упавших потомков, Childspec — описание потомков.

Рассмотрим пример из супервизора, котролирующего сервер.

Сервер:

-module(testotp_ser).
-behaviour(gen_server).

-export([start_link/0]).
-export([init/1,handle_call/3,handle_cast/2]).

%% let's start a server and register it locally
%% with the name 'testotp_ser'.

start_link() ->
        gen_server:start_link({local,testotp_ser},
                testotp_ser,[],[]).

init(_Args) ->
        {ok,ok}.

handle_call(test,_From,Chs) ->
        io:format("This is a handle_call~n",[]),
        {reply,Chs,Chs}.

handle_cast({test_cast,Ch},Chs) ->
        io:format("This is handle_cast~n",[]),
        {noreply,Chs}.
Супервизор:
-module(testotp_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
start_link() ->
        supervisor:start_link(testotp_sup,[]).
%% let's start a child process from the testotp_ser module
init(_Args) ->
        {ok, {{one_for_one, 1, 60},
                [{testotp_ser,{testotp_ser,start_link,[]},
                        permanent,brutal_kill,worker,[testotp_ser]}]}}.

 

Соберем и запустим этот пример:

1> c(testotp_ser).
2> c(testotp_sup).
3> testotp_sup:start_link().
4> gen_server:call(testotp_ser,test).
This is a handle_call
ok
5> gen_server:cast(testotp_ser,{test_cast,a}).
This is handle_cast
ok

Sum it up.

Итак, основная часть идеи OTP состоит в построении деревьев контроля и в использовании поведений. При использовании поведений необходимо просто реализовать специфичную для данного модуля функциональность в в виде набора коллбеков. Общую для всех приложений часть поведения берет на себя система. При правильном использовании OTP вы получите надежный, хорошо читаемый код. В следющий раз мы поговорим о системе релизов в OTP. Удачи!

Действия с Документом