在前两个服务器里,代码升级和事务语义是分开的。现在把它们组合到一个服务器里。
-module(server4).
-author("DQ").
%% API
-export([start/2, swap_code/2, rpc/2]).
start(Name, Mod) ->
register(Name, spawn(fun() -> loop(Name, Mod, Mod:init()) end)).
swap_code(Name, Mod) -> rpc(Name, {swap_code, Mod}).
rpc(Name, Request) ->
Name ! {self(), Request},
receive
{Name, crash} -> exit(rpc);
{Name, ok, Response} -> Response
end.
loop(Name, Mod, OldState) ->
receive
{From , {swap_code, NewCallbackMod}} ->
From ! {Name, ok, ack},
loop(Name, NewCallbackMod, OldState);
{From, Request} ->
try Mod:handle(Request, OldState) of
{Response, NewState} ->
From ! {Name, ok, Response},
loop(Name, Mod, NewState)
catch
_: Why ->
log_the_error(Name, Request, Why),
From ! {Name, crash},
loop(Name, Mod, OldState)
end
end.
log_the_error(Name, Request, Why) ->
io:format("Server ~p request ~p~n"
"caused exception ~p~n",
[Name, Request, Why]).
这个服务器同时提供了热代码交换和事务语义,干净利落!