Maintaining State loop(State) -> receive % handle messages here, % messages may affect State end, loop(NewState). 46 Monday, June 18, 12 46
Maintaining State loop(State) -> receive % handle messages here, % messages may affect State end, loop(NewState). 47 Monday, June 18, 12 47
But State is Immutable! 48 Monday, June 18, 12 48
Erlang Immutability • Erlang assignment is pattern matching, not mutation • If a variable is unbound, it is bound to the value of the right-hand side • If bound, its value is matched against the right-hand side • if match, return value • if no match, throw badmatch exception 49 Monday, June 18, 12 49
Maintaining State loop(State) -> NewState = receive % handle messages here, % messages may affect State end, loop(NewState). 50 Monday, June 18, 12 50
Maintaining State loop(State) -> NewState = receive % handle messages here, % messages may affect State end, loop(NewState). 51 Monday, June 18, 12 51
Maintaining State loop(State) -> NewState = receive % handle messages here, % messages may affect State end, loop(NewState). 52 Monday, June 18, 12 52
Common vs. App- Specific Common App-Specific Loop Management State Management Message Reception Message Handling and Dispatch Invoking Callbacks Handling Callbacks 53 Monday, June 18, 12 53
Callbacks with State loop(Callbacks, State) -> NState = receive {message, Val} -> Callbacks:handle(Val, State) end, loop(Callbacks, NState). 54 Monday, June 18, 12 54
Callbacks with State loop(Callbacks, State) -> NState = receive {message, Val} -> Callbacks:handle(Val, State) end, loop(Callbacks, NState). 55 Monday, June 18, 12 55
Callbacks with State loop(Callbacks, State) -> NState = receive {message, Val} -> Callbacks:handle(Val, State) end, loop(Callbacks, NState). 56 Monday, June 18, 12 56
Multiple Messages loop(Callbacks, State) -> NState = receive {message1, M1} -> Callbacks:handle1(M1,State); {message2, M2} -> Callbacks:handle2(M2,State); Other -> Callbacks:handle_other( Other,State) end, loop(Callbacks, NState). 57 Monday, June 18, 12 57
Controlling the Loop loop(Callbacks, State) -> {LoopAction, NState} = receive {message1, M1} -> Callbacks:handle_m1(M1,State); {message2, M2} -> Callbacks:handle_m2(M2,State); Other -> Callbacks:handle_other(Other,State) end, case LoopAction of stop -> ok; _ -> loop(Callbacks, NState) end. 58 Monday, June 18, 12 58
Controlling the Loop loop(Callbacks, State) -> {LoopAction, NState} = receive {message1, M1} -> Callbacks:handle_m1(M1,State); {message2, M2} -> Callbacks:handle_m2(M2,State); Other -> Callbacks:handle_other(Other,State) end, case LoopAction of stop -> ok; _ -> loop(Callbacks, NState) end. 59 Monday, June 18, 12 59
Behavior Loops • These are the basics • Actual OTP behavior loops are more sophisticated, integrating with underlying OTP system • gen_server , gen_fsm , supervisor , etc. all assume specific callbacks, checked by the compiler 60 Monday, June 18, 12 60
gen_server 61 Monday, June 18, 12 61
gen_server • Generic server behavior • Supports server-like components, not necessarily distributed • “Business logic” lives in app-specific callback module 62 Monday, June 18, 12 62
gen_server Process Startup • start_link(Module, Args, Options) -> Result • or start_link(ServerName, Module, Args, Options) -> Result • ServerName is typically {local, Name} where Name becomes the registered process name • Module is the callback module 63 Monday, June 18, 12 63
gen_server Process Startup • start_link calls Module:init/1 callback • init typically returns {ok, State} where State is the new app-specific state of the gen_server process • State is usually an Erlang record (a collection of fields, can get and set by name) 64 Monday, June 18, 12 64
gen_server Call • Allows caller to make a synchronous call to the server • call(ServerRef, Request) -> Reply call(ServerRef, Request, Timeout) -> Reply • ServerRef is the name or pid of the gen_server process • Request is any term, typically an atom or tuple 65 Monday, June 18, 12 65
gen_server Call • Call invokes Module:handle_call/3 callback • Arguments are Request, From, State • Request is passed thru from gen_server:call • From identifies the calling client process • State is the gen_server app state 66 Monday, June 18, 12 66
gen_server Call • handle_call returns reply , noreply , or stop • {reply, Reply, NewState} or • {noreply, NewState} or • {stop, Reason, Reply, NewState} or {stop, Reason, NewState} • Replies go back to calling process • If no reply, it must be supplied later via gen_server:reply/2 67 Monday, June 18, 12 67
gen_server Cast • Allows caller to make a fire-and- forget call to the server (no reply) • cast(ServerRef, Request) -> ok • ServerRef is the name or pid of the gen_server process • Request is any term, typically an atom or tuple 68 Monday, June 18, 12 68
gen_server Cast • Call invokes Module:handle_cast/2 callback • Arguments are Request, State • Request is passed thru from gen_server:cast • State is the gen_server state 69 Monday, June 18, 12 69
gen_server Cast • handle_cast returns noreply or stop • {noreply, NewState} or • {stop, Reason, NewState} • Either way, no reply to calling process 70 Monday, June 18, 12 70
handle_info Callback • The Module:handle_info/2 callback is called when a message arrives for the gen_server process • {noreply, NewState} or • {stop, Reason, NewState} 71 Monday, June 18, 12 71
terminate Callback • Opposite of init/1 , called when gen_server process is exiting • Allows application to clean up 72 Monday, June 18, 12 72
gen_server process gen_server:start_link Module:init gen_server:call Module:handle_call State gen_server:cast Module:handle_cast Module:handle_info message Loop 73 Monday, June 18, 12 73
gen_server Interface • Provide a set of app-specific functions in your callback module as your interface • Hide the fact that your module is a gen_server • Allows you to change the module later without breaking clients 74 Monday, June 18, 12 74
gen_server Example -module(key_value). -behavior(gen_server). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -export([start_link/0, stop/0, store/2, lookup/1, delete/1]). 75 Monday, June 18, 12 75
key_value Start & Stop start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). stop() -> gen_server:cast(?MODULE, stop). 76 Monday, June 18, 12 76
key_value Start & Stop start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). stop() -> gen_server:cast(?MODULE, stop). 76 Monday, June 18, 12 76
key_value Start & Stop start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). stop() -> gen_server:cast(?MODULE, stop). 76 Monday, June 18, 12 76
key_value Start & Stop start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). stop() -> gen_server:cast(?MODULE, stop). 76 Monday, June 18, 12 76
key_value Start & Stop start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). stop() -> gen_server:cast(?MODULE, stop). 76 Monday, June 18, 12 76
key_value Start & Stop start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). stop() -> gen_server:cast(?MODULE, stop). 76 Monday, June 18, 12 76
key_value Start & Stop start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). stop() -> gen_server:cast(?MODULE, stop). 76 Monday, June 18, 12 76
key_value API store(Key, Value) -> gen_server:call(?MODULE, {store, Key, Value}). lookup(Key) -> gen_server:call(?MODULE, {lookup, Key}). delete(Key) -> gen_server:cast(?MODULE, {delete, Key}). 77 Monday, June 18, 12 77
key_value API store(Key, Value) -> gen_server:call(?MODULE, {store, Key, Value}). lookup(Key) -> gen_server:call(?MODULE, {lookup, Key}). delete(Key) -> gen_server:cast(?MODULE, {delete, Key}). 77 Monday, June 18, 12 77
Recommend
More recommend