Chicago Erlang Users Group presentation given June 2, 2010 at Orbitz WorldWide in Chicago by John Patton and Tristan Sloughter. The presentation covers a high-level overview of the OTP gen_server behaviour by gradually building up to it using non-OTP concepts.
CEUG: Introduction to OTP Behaviors, Part I - gen_server
1. Intro to OTP Behaviours
Presenters: John Patton and Tristan Sloughter
2. What we’ll cover
• Build concepts over the course of the
presentation to create a general server
architecture
• Assumption: basic Erlang knowledge
• We’ll have time for Q&A at the end
3. What are we going to do?
• Look at high-level concepts used in making a
simple chat server
• Start off using basic Erlang!!!
• Let’s understand the concepts first
• Build on top of concepts until we
understand how a general server framework
works under the hood
5. Simple Chat Server
What kind of things does a simple chat server need?
• Startup routine
• Server needs to be aware of the clients that are
connected
• Clients need to register and unregister with the server
• The server needs to facilitate sending chat messages from
one client to another
• Shutdown routine
8. Chat Server Receive loop
• Our chat server’s loop function
is spawned and registered
chat_server
• The chat server loop function
will maintain the dictionary of
clients (client name -> pid) receive loop
{register_client,...}
loop {unregister_client,...}
• Traditional tail recursion, will run {send_message,...}
{stop,...}
until a stop message is received
loop()
• Messages sent from a client are
handled within the receive loop
9. Let’s organize startup start_link
and initialization spawn
• Create an initialization function
to handle registering self()
init
‘chat_server’
• Wrap the spawn inside a
start_link function
•
receive loop
Instead of spawning loop, let’s {register_client,...}
spawn the init function and call loop {unregister_client,...}
{send_message,...}
loop {stop,...}
loop()
10. Where should we keep start_link
track of our clients? spawn
• Let’s make use of an internal
state, a key-value dictionary
init
‘chat_server’
• Init will be responsible for dict:new()
creating the server’s State:
{ClientName, ClientPID} State
receive loop
•
{register_client,...}
State will be passed into and loop {unregister_client,...}
{send_message,...}
maintained within the receive {stop,...}
loop
loop(State)
11. Let’s look back at
where we started
client defined elsewhere
chat_server chat_server
chat_server ! {register_client, Name, Pid}.
chat_server ! {send_message, To, Msg}.
receive loop
chat_server ! {unregister_client, Name}.
{register_client,...}
... loop {unregister_client,...}
{send_message,...}
{stop,...}
loop()
12. Take a look at
where we are. start_link
spawn
client defined elsewhere
chat_server
chat_server ! {register_client, Name, Pid}.
chat_server ! {send_message, To, Msg}. init
‘chat_server’
chat_server ! {unregister_client, Name}. ! dict:new()
... State
receive loop
{register_client,...}
loop {unregister_client,...}
{send_message,...}
{stop,...}
loop(State)
13. Let’s make it easier for the
client to bang messages
start_link
spawn
• “API” Functions in the
chat_server module
that a client can call init
‘chat_server’
register_client dict:new()
State
•
unregister_client
API functions facilitate ! loop
receive loop
{register_client,...}
banging messages to the send_message {unregister_client,...}
{send_message,...}
{stop,...}
server pid for the client stop
loop(State)
• Cleans up the code
14. Let’s make a handler for
banged messages start_link
spawn
• “Callback” functions in
a module that will
implement the init
‘chat_server’
register_client dict:new()
message functionality State
unregister_client
• Turns message loop send_message
! loop
receive loop
{register_client,...}
{unregister_client,...}
into an interface {send_message,...}
{stop,...}
stop
• Separates the loop(State)
implementation from
handle_receive
the interface {Message, State}
•
terminate
Callbacks update state
15. Why use OTP?
• Large collection of libraries
• Unified Application packaging and release structure
• Standardized coding practices
• Components: HTTP and FTP server, CORBA
ORB, SNMP Agent, IDL, Error Handling
• Formalized design patterns into
“behaviors”
16. What is an OTP
behavior? OTP Behavior
• gen_*:functionA/3
• Simply: a formalization of a • gen_*:functionB/2
common pattern into two
parts. ...
• Behavior Module that defines
the pattern interface.
Callback Module
• Callback Module that • module:callbackA/2
implements the pattern
interface. • module:callbackB/3
...
17. Why use OTP for our server?
• Much of the code needed to create the server in
our example is already written in the OTP
behavior: gen_server
• Since the interface is only used to call a callback
function, the callbacks can be in any module
• The gen_server has a generic set of behavior
functions available for use by ANY implementation
(can use more than one callback implementation)
18. Behavior: gen_server
chat server gen_server ! callback
chat_server:start_link gen_server:start_link callback:init/1
chat_server:send_message gen_server:call callback:handle_call/3
chat_server:register_client gen_server:multi_call
chat_server:unregister_client
chat_server:stop gen_server:cast callback:handle_cast/2
sends stop message returns: {stop, normal, State}
callback:terminate/2
State is maintained here State is passed in and returned back here
19. More Information
• Client-server design principles:
http://www.erlang.org/doc/design_principles/
gen_server_concepts.html
• gen_server “behaviour”:
http://www.erlang.org/doc/man/gen_server.html
• Chicago Erlang Users Group: start a discussion!
• Me: John Patton <jpatton@gmail.com>
Remove &#x201C;OTP&#x201D;: just say youre developing a framework for a general server arch
I'd move the 3rd bullet to second bullet, reword it without a specific gen_server reference, say we will build these concepts into a general framework, something like that..
then the 3rd bullet can be we will show erlang's already existing framework, and why to use it instead
move the spawn and registering bit to slide 9
just focus on the loop first
if you are going to use "behavior", stick with it, otherwise just use "behavior" everywhere and not make a reference to its english counterpart
Revisit verb tense on all bullets
Much More:
* A major objective of the OTP is to provide a highly productive environment for designing applications.
so 16 is really good, just when you talk, make sure to refer back to your initial guiding example you started with
A Behaviour Module is a generic collection of functions provided by OTP.
Callback Module is an implementation of a pre-defined set of functions expected by the behaviour.