gen_server练习

制作一个 任务中心

-module(job_centre).
-behaviour(gen_server).

-export([start_link/0, add_job/1, work_wanted/0, job_done/1, statistics/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2, code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {queue = queue:new(), in_progress = [], completed = [], workers = [], id = 0}).

start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
add_job(F) -> gen_server:call(?SERVER, {add_job, F}).
work_wanted() -> gen_server:call(?SERVER, work_wanted).
job_done(JobNumber) -> gen_server:cast(?SERVER, {job_done, JobNumber}).
statistics() -> gen_server:call(?SERVER, statistics).

init([]) -> {ok, #state{}}.

handle_call({add_job, F}, _From, State) ->
    Id = State#state.id + 1,
    Queue = queue:in({Id, F}, State#state.queue),
    {reply, Id, State#state{queue= Queue, id = Id}};

handle_call(work_wanted, _From, State) ->
    case queue:out(State#state.queue) of
        {empty, _} ->
            {reply, no, State};
        {{value, {JobNumber, F}}, NewQueue} ->
            % 启动监控
            WorkerPid = self(),
            erlang:monitor(process, WorkerPid),
            InProgress = [JobNumber | State#state.in_progress],
            Workers = [{JobNumber, WorkerPid, F} | State#state.workers],
            {reply, {JobNumber, F}, State#state{queue = NewQueue, in_progress = InProgress, workers = Workers}}
    end;

handle_call(statistics, _From, State) ->
    {reply, {queue:len(State#state.queue), length(State#state.in_progress), length(State#state.completed)}, State}.

handle_cast({job_done, Id}, State) ->
    io:format("Job ~p is done~n", [Id]),
    Completed = [Id | State#state.completed],
    InProgress = lists:delete(Id, State#state.in_progress),
    {noreply, State#state{in_progress = InProgress, completed = Completed}}.

handle_info({'DOWN', _, process, WorkerPid, _Reason}, State) ->
    {Id, _WorkerPid, F} = lists:keyfind(WorkerPid, 2, State#state.workers),
    Queue = queue:in({Id, F}, State#state.queue),
    InProgress = lists:delete(Id, State#state.in_progress),
    {noreply, State#state{queue = Queue, in_progress = InProgress, workers = lists:keydelete(WorkerPid, 2, State#state.workers)}};
handle_info(_Info, State) -> {noreply, State}.

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

在这里插入图片描述

-module(job_centre_test).
-include_lib("eunit/include/eunit.hrl").
-export([test/0]).

start_job_centre() ->
	job_centre:start_link(),
	ok.
stop_job_centre() ->
	gen_server:call(?MODULE, stop),
	ok.
simulate_worker_crash() ->
	receive
		{'DOWN', _, process, _, _Reason} ->
			io:format("工作进程挂掉~n")
	after 0 ->
	io:format("超时~n")
end.
test() ->
%% 在erlang中使用单元测试判断函数值是否符合预期
	?assertEqual(ok, start_job_centre()),
	F = fun() -> io:format("Task 1") end,
	?assertEqual(1, job_centre:add_job(F)),
	?assertEqual({1, F}, job_centre:work_wanted()),
	simulate_worker_crash(),
	?assertEqual({1, F}, job_centre:work_wanted()),
	stop_job_centre().

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值