应用程序服务器和监控树

应用程序有两个服务器:一个质数服务器和一个面积服务器。

质数服务器

这里是质数服务器的代码,它是用gen_server行为编写的:

-module(prime_server).
%%%=======================EXPORT=======================
-export([new_prime/1, start_link/0]).

%% gen_server callbacks
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
%%%=======================INCLUDE======================
%%%=======================RECORD=======================
-record(state, {}).
%%%=======================DEFINE=======================
%%%=======================TYPE=========================
%%%=================EXPORTED FUNCTIONS=================
%% ----------------------------------------------------
%% Description: Starts the server
%% ----------------------------------------------------
start_link() ->
	gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

new_prime(N) ->
	%% 20000(ms)是一个超时设置
	gen_server:call(?MODULE, {prime, N}, 20000).

%%%===============gen_server callbacks=================
%% ----------------------------------------------------
%% Description: Initializes the server
%% ----------------------------------------------------
init([]) ->
	process_flag(trap_exit, true),
	io:format("~p starting~n", [?MODULE]),
	{ok, 0}.
%% ----------------------------------------------------
%% Description: Handling call messages
%% ----------------------------------------------------
handle_call({prime, K}, _From, N) ->
	{reply, make_new_prime(K), N + 1}.

%% ----------------------------------------------------
%% Description: Handling cast messages
%% ----------------------------------------------------
handle_cast(_Msg, N) ->
	{noreply, N}.

%% ----------------------------------------------------
%% Description: Handling all non call/cast messages
%% ----------------------------------------------------
handle_info(_Info, N) ->
	{noreply, N}.

%% ----------------------------------------------------
%% Description:
%% ----------------------------------------------------
terminate(_Reason, _N) ->
	io:format("~p stopping ~n", [?MODULE]),
	ok.

%% ----------------------------------------------------
%% Description: Convert process state when code is changed
%% ----------------------------------------------------
code_change(_OldVsn, N, _Extra) ->
	{ok, N}.

make_new_prime(K) ->
	if
		K > 100 ->
			alarm_handler:set_alarm(tooHot),
			N = lib_primes:make_prime(K),
			alarm_handler:clear_alarm(tooHot),
			N;
		true ->
			lib_primes:make_prime(K)
	end.

%%%===================LOCAL FUNCTIONS==================
%% ----------------------------------------------------
%% Description:
%% ----------------------------------------------------

面积服务器

现在轮到面积服务器了,它也是用gen_server行为编写的。在编写这个示例时剪切粘贴了质数服务器里的代码,然后把它转变成面积服务器。用这种方式编写服务器速度极快。

-module(area_server).
%%%=======================EXPORT=======================
-export([area/1, start_link/0]).

%% gen_server callbacks
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
%%%=======================INCLUDE======================
%%%=======================RECORD=======================
-record(state, {}).
%%%=======================DEFINE=======================
%%%=======================TYPE=========================
%%%=================EXPORTED FUNCTIONS=================
%% ----------------------------------------------------
%% Description: Starts the server
%% ----------------------------------------------------
start_link() ->
	gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

area(Thing) ->
	gen_server:call(?MODULE, {area, Thing}).

%%%===============gen_server callbacks=================
%% ----------------------------------------------------
%% Description: Initializes the server
%% ----------------------------------------------------
init([]) ->
	%% 如果想让terminate/2在应用程序停止时被调用,就必须设置trap_exit = true
	process_flag(trap_exit, true),
	io:format("~p starting~n", [?MODULE]),
	{ok, 0}.
%% ----------------------------------------------------
%% Description: Handling call messages
%% ----------------------------------------------------
handle_call({area, Thing}, _From, N) ->
	{reply, compute_area(Thing), N + 1}.

%% ----------------------------------------------------
%% Description: Handling cast messages
%% ----------------------------------------------------
handle_cast(_Request, N) ->
	{noreply, N}.

%% ----------------------------------------------------
%% Description: Handling all non call/cast messages
%% ----------------------------------------------------
handle_info(_Info, N) ->
	{noreply, N}.

%% ----------------------------------------------------
%% Description:
%% ----------------------------------------------------
terminate(_Reason, _State) ->
	io:format("~o stopping~n", [?MODULE]),
	ok.

%% ----------------------------------------------------
%% Description: Convert process state when code is changed
%% ----------------------------------------------------
code_change(_OldVsn, N, _Extra) ->
	{ok, N}.

compute_area({square, X})       -> X * X;
compute_area({rectongle, X, Y}) -> X * Y.

%%%===================LOCAL FUNCTIONS==================
%% ----------------------------------------------------
%% Description:
%% ----------------------------------------------------
编写完了应用程序代码,还加了一个小错误。现在必须设立一个监控结构来检测和纠正所有可能在运行时发生的错误。

监控树

监控树是一种由进程组成的树形结构。树的上级进程(监控器)监视着下级进程(工作器),如果下级进程挂了就会重启它们。监控树有两种:
一对一监控树
在一对一监控里,如果某个工作器崩溃了,就会被监控器重启。
一对多监控树
在一对多监控里,如果任何一个工作器崩溃了,所有工作进程都会被终止(通过调用相应回调模块里的terminate/2 函数)然后重启。
监控器是用 OTP supervisor 行为创建的。这个行为用一个回调模块作为参数,里面指定了监控策略以及如何启动监控树里的各个工作进程。监控树通过以下形式的函数指定:
init(...) ->
    {ok, 
        {RestartStrategy, MaxRestarts, Time},
        [Worker1, Worker2, ...]
    }}.
            
这里的 RestartStrategy 是原子 one_for_one one_for_all MaxRestarts Time 则指定“重启频率”。如果一个监控器在Time 秒内执行了超过 MaxRestarts 次重启,那么这个监控器就会终止所有工作进程然后退出。这是为了防止出现一种情形,即某个进程崩溃、被重启,然后又因为相同原因崩溃而形成的无限循环。
而其中Worker1 Worker2 这些是描述如何启动各个工作进程的元组。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值