Erlang/OTP Callback Modules II
April 23, 2009
Hynek (Pichi) Vychodil kindly pointed me to Joe Armstrong’s thesis to help deepen my understanding of callback modules.
Starting on page 98, Joe talks about “abstracting out concurrency.”
Keeping track of many concurrent process is mentally challenging and error-prone, he says. For this reason he advocates a library of generic components, written by skilled Erlang programmers, and “plugins,” written by programmers competent in Erlang sequential programming. This component library, of course, has become OTP.
Says Joe, “The generic component should hide details of concurrency and mechanisms for fault-tolerance from the plugins. The plugins should be written using only sequential code with well-defined types.”
My quick reading did not turn up the phrase “callback module.” May be there. But I take it that “callback module” and “plugin” are synonymous.
Check out Joe’s thesis for yourself. Tons of invaluable background straight from the man himself.
One crucial point still clouds my aging brain: When you call a function in, say, a gen_server callback module and, say, it returns a tuple like {ok, yada yada}, who’s listening and expected to respond? I definitely need to think this one through before I get back to my walk-through of iserve.
Meanwhile, I’m packing up for Erlang University. Plan to spend three days learning what I can from Chris Anderson and Jan Lehnard about CouchDB.
The following two days, Thursday and Friday, promise many hours of brain food. I’m particularly looking forward to Rusty Klophaus’s Nitrogen presentation. If you haven’t been following Google Groups Nitrogen Web Framework for Erlang, drop in. Lively exchange of performance profiling data has been particularly interesting.
While rubbing shoulders with Erlang greats at Erlang University, I also hope to learn much more about Web Machine and Erlyweb.
Can’t promise, but maybe I’ll come back with a few pearls of wisdom. Maybe even a photo or two. I certainly plan to get back to my dissection of iserve.
So, be back sometime in early May just as soon as the jet lag wears off.
Erlang/OTP Callback Modules
April 22, 2009
Apologies for my April 19, 2009 post. For one thing, it’s much too dense. And worse, it’s wrong — at least seven of the last eight paragraphs.
Reading Erlang source really shouldn’t be rocket science. But I’m still struggling to follow the flow-of-control through Erlang applications.
One problem, for me, is this concept of “callback module.” I think I understand it, but the more I think about it the less confident I feel. I’ve tried to find a definition in Google, but failed. It seems to be one of those terms that everyone tosses around thinking that everyone else understands it.
But if I’m hazy, chances are there’s another Newbie or two out there scratching his/her head as well.
Problem for this Newbie is that the concept of “callback module” implies that something is going on behind the curtains. If I’m not all that clear about what’s going on back there, how can I be clear about what’s going on in the foreground?
So here’s my Newbie insight for the day. Caution: it may be wrong. If so, I beseech any passing Erlang wizard to set me straight.
Behaviours in Erlang/OTP are functional templates of oft-repeated code patterns, e.g., servers, finite-state machines, events, supervisors, and applications.
Callback modules fill in the slots in these templates to round out functionality for specific purposes. The “behaviour” is the generic, or abstract, part of the functionality. The “callback module” is the means through which the programmer tailors a behavior for specific application.
So how do we find out what’s going on behind the curtain? Erlang/OTP docs should certainly be our first stop:
Gen_Server Behaviour
“The client-server model is characterized by a central server and an arbitrary number of clients. The client-server model is generally used for resource management operations, where several different clients want to share a common resource. The server is responsible for managing this resource.”
Gen_Fsm Behaviour
“A finite state machine, FSM, can be described as a set of relations of the form:
“State(S) x Event(E) -> Actions(A), State(S’)
“These relations are interpreted as meaning:
“If we are in state S and the event E occurs, we should perform the actions A and make a transition to the state S’.”
Gen_Event Behaviour
“In OTP, an event manager is a named object to which events can be sent. An event could be, for example, an error, an alarm or some information that should be logged.”
Supervisor Behaviour
“A supervisor is responsible for starting, stopping and monitoring its child processes. The basic idea of a supervisor is that it should keep its child processes alive by restarting them when necessary.”
Applications
“When we have written code implementing some specific functionality, we might want to make the code into an application, that is a component that can be started and stopped as a unit, and which can be re-used in other systems as well.”
I’ll pick up on iserve again tomorrow; and try to view it from high overhead with these “behaviours” in mind.
Our recent (March 30, April 3, and April 6) explorations into Christian Sunesson’s fork of iserve taught us much about OTP/Erlang functionality and conventions, including directory structures, supervision, and gen-server functionality.
In the April 6 post we explored how iserve’s start-up logic created two child processes, a supervisor, iserve_server_sup, and a gen_server, iserve_master.
Now we’re in a position to plunge deeper into the heart of iserve. So let’s poke into iserve_server_sup.
There’s repetition of material from earlier posts here. Think of it as cram review before your midterm.
And, all due cautions here: beware possible Newbie misunderstandings or misinterpretation in what follows. As always, I invite corrections.
First, note the -behavior(supervisor) directive. This tells us that iserve_server_sup is an interface to the supervisor pattern in OTP/Erlang.
iserve_server_sup exports four functions: start_link/0, start_link/1, add_server/2, and init/1.
Recall that during the iserve start_up sequence, iserve_sup created a supervisory process registered as iserve_sup. iserve_sup’s initialization process, iserve_sup:init/1, in turn, called iserve_server_sup:start_link/1, passing in iserve_sup’s PID in the variable Supervisor.
The function iserve_server_sup:start_link/1 creates and registers a new second-level supervisory process called iserve_server_sup. The name is defined in the macro SERVER declared in the -define directive at the top of the module source listing.
When the supervisory process iserve_server_sup is created, supervisor:start_link/3 calls init/1, which initializes the new supervisory process.
iserve_server_sup:init/1 first instantiates the variable AChild with a tuple that defines a call to iserve_server, then fires off the message {ok, {{simple_one_for_one,10,300},[AChild]}}.
So who’s waiting with abated breath for this message?
The OTP/Erlang generic supervisor. The message defines a simple_one_for_one restart strategy for iserve_server_sup, with no more than 10 restarts within 300 seconds. AChild defines which child processes iserve_server_sup should start and monitor.
The value of AChild is:
{iserve_server,{iserve_server,start_link,[iserve_master]},
temporary,2000,worker,[iserve_server]}
So how do we interpret all this? We’ve gone through this before, but let’s it again (nothing like repetition to sharpen the Newbie mind):
iserve_server – a name used to identify the child specification by the supervisor.
iserve_server, start_link,[iserve_master] – Start function in form of M,F,A; e.g. iserve_server:start_link(iserve_master).
temporary – restart function.
2000 – Shutdown. The supervisor will tell the child process to terminate by calling exit(Child,shutdown) and then wait for an exit signal with reason shutdown back from the child process. If no exit signal is received within the specified time, 2000 seconds in our case, the child process is unconditionally terminated using exit(Child,kill).
worker – child type
iserve_server – Module; used by the release handler during code replacement to determine which processes are using a certain module. Module is the callback module, if the child process is a supervisor, gen_server or gen_fsm.
(April 22, 2009 — Mea Culpa!: I think I stepped off the track when I wrote the following. Don’t believe a word of it. I’ll revisit as soon as I’m more confident that I know what I’m talking about. LRP)
So it’s looking like the supervisor iserve_server_sup is going to be looking after the gen_server iserve master.
Let’s check it out by poking into iserve_master.
First off, Christian tells us that iserve_master provides “Bookkeeping of running servers.”
Next, the -behavior(gen_server) tells us that it provides the callback functions for gen_server.
I hesitate to plow through the bloody details of gen_server. Been there. Done that. So I won’t. You can read about it here.
For our purposes, the things to note are the internal functions call_add_server and call_del_server.
Now these look interesting, but by now you’re undoubtedly bored to tears and I’m running out of pep.
So let’s pick it up another day.
Web Templates for Erlang: Continued from previous post
April 7, 2009
“8) If we fore go fancy GUI content editing and styling tools, then this system can be fairly simple to implement; puts no added burden on the one-man-band web site developer.
9) In my experience with systems that conceptually approach this model I’ve seen substantial acceleration of productivity.
So, I argue, divide and conquer! “
Fact is, this is the kind of system I’m working toward. Would welcome Erlang wizard input.
Web Templates for Erlang: A Different Take
April 7, 2009
Much discussion of web templates on the Google Groups – Nitrogen forum recently.
I stuck in my two cents and generated some interesting discussion.
This is a topic I care a bunch about based on experience and hard knocks.
Today I posted the rationale behind my thinking, thought I’d share it.
Note, I define a “Part” as an encapsulated single-function black box of code that can be configured to display CSS stylized web content. You can think component, applet, mini-application, or what have you.
So here it is:
“I’d venture that the truest thing one can say about templates is, ‘different horses for different courses.’
Page-level, monolithic templates are fine for relatively simple pages.
But I argue that there is a conceptual mismatch between the way many web developers, particularly those on the programming side, see the web and the way many many sites are presented today, indeed, the way many page content developers and designers conceptualize a web page.
On the one hand, the conceptual unit is the ‘page.’ Makes sense, since the page is the basic unit of HTML.
But for well-trained designers the page is simply a frame for a ‘page grid.’ Squint your eyes and look at any magazine, newspaper, or even well-designed brochure, and you’ll see a mathematical “grid” structure, where each panel in the grid is a container for content. True, many designers spread content over two or more panels, but the basic structure holds.
The grid system is a fundamental concept in many graphic design text books. Why? Because it provides a coherent way of organizing disparate elements of content.
Squint at many, if not most, well-designed, high-traffic websites and you’ll see the grid system at work organizing the content. The grid system is like a well-organized closet with shelves and cubby holes — everything has a place and everything is in its place, whereas a page-oriented design is more like one of my wife’s kitchen drawers, everything tossed in a jumble with everything else (I should talk; my closets and drawers are even more disorganized).
Now take a look at amazon.com. I have no idea of how Amazon constructs its pages. Maybe as someone suggested it’s a big hairy content management system. Doesn’t matter to my basic argument.
Call up page source for the Amazon home page. Now squint your eyes and substitute variables for every substantive element; e.g. in your mind, turn the source into a template. Now imagine a programmer giving you a list of variable names for different dynamic content elements and working through the template to match content item with place-holder in your big, long, hairy template file.
I’m sure no one does it quite this way, but you get the idea.
Now take another look at Amazon’s home page. Squint your eyes and you’ll see a simple three-column grid, or “make-up” as a designer would say; e.g. left and right side bars surrounding a main content panel.
Look more closely at the top of the grid and you’ll see three content elements (personalization line, personal menu, and search bar) that span the content column and right side bar. They’re still consistent with the basic grid, but they add visual diversity and interest while keeping content well organized.
Further note that the basic columns contain simple lists of content elements stacked one atop another.
Now, look at the variety of content elements that fill the panels in the grid and think about the code, HTML formating, and CSS styling tags needed to create each element. You’ll note that some elements are straight text, some are text and graphics, some made up of hyper links, some form elements, some buttons, and some report data drawn up from a database.
When I talk about ‘Parts,’ this is essentially what I’m talking about. Content elements can be abstracted into a set of ‘Parts,’ distinguished by underlying logic.
Now imagine a page construction process that goes like this:
1) Programmers provide an inventory of Parts, single-function black boxes of code that can be configured with content and styling to generate content elements.
2) Select the Parts you need to convey the information you want. Enter content for each.
3) Design (or select from an inventory) a page grid, essentially a list of DIVs (see my earlier post for example).
4) Develop (or select from inventory) CSS file(s) for your page
5) Plug parts into the page grid
6) Tweak styles in each part if necessary to maintain stylistic consistency with page.
A system like this:
1) Is conceptually consistent with the way content developers and trained designers think
2) Does not necessarily require the page designer to adopt any additional tools beyond HTML and CSS.
3) Breaks down a potentially confusing task into a set of relatively simple tasks.
4) Content and styling can be configured with a simple text editor on the one hand, or sophisticated GUI tools on the other. Indeed, GUI tools could be an additional layer on top of the simpler system.
If the base system were open-source, then specialized parts and GUI systems could add value to meet specialized requirements or support a variety of business models.
E.g., Parts could be open-source or proprietary; offering the best of both worlds.
5) Encourages substantial code reuse.
6) Pushes code complexity down into the Parts. With careful factoring, code complexity may never even be an issue but for the rarest and most algorithmically challenging Parts.
7) Offers great flexibility. Change the page grid and/or the high-level CSS file and you change the basic look of the page. Reuse content elements across pages. Change a content element with little to no interaction with other content elements.”
(Getting too long here… continued next post)
Newbie Test: iserve – Oh oh… Beware!
April 7, 2009
Just spotted this on Christian Suneson’s blog…
“I probably broke iserve build-simplicity tonight.”
Don’t know if Christian has fixed it yet. But if you have trouble bringing up iserve, it’s a good guess that Christian’s on the case.
Newbie Test: iserve – start-up logic
April 6, 2009
In our last two posts, March 30 and April 3, we poked into Erlang/OTP conventions, supervisor processes, and application resource files.
Yes, I know, this is supposed to be a Newbie Test. Well, it is. But the opportunity to study how iserve is set up as an Erlang/OTP application is just too good to pass up.
Newbies need to nibble down nifty knowledge at every pass.
iserve’s application resource file, iserve.app, tells us that we must poke into iserve_sup.erl to see how iserve is fired up.
As noted in our March 30 post, you can recognize iserve_sup.erl as a supervisor callback module by its name, *_sup.erl, and the -behviour(supevisor) directive near the top of the iserve_sup.erl module.
iserve_sup.erl exports two functions: start_link/0 and init/1.
Here’s start_link/0.
start_link() -/>
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
supervisor:start_link/3 creates a supervisor process as part of a supervision tree and ensures that the supervisor is linked to the calling process (its supervisor).
Note that the first parameter of supervisor:start_link/3 is of the form {local,Name}.
This means that the supervisor is registered locally as Name using register/2.
register/2 expects a name, Name, and a process identity, P. It associates Name with the port or process identity P.
The second parameter is the name of the callback module, in this case, iserve_sup.erl.
The third parameter is an argument passed to init/1.
So, we fire off iserve:start_link/0. This kicks off a locally registered supervisor process with the name iserve_sup. Our new supervisor now calls init/1 to find out about restart strategy, maximum restart frequency and child processes.
In our case, init/1 starts two new child processes, a supervisors, iserve_server_sup, and a gen_server, iserve_master.
We looked at how supervisor processes are configured in our March 30 post.
Christian kindly provides source comments to help us understand the functions of these two processes:
-
%% The servers supervisor is for keeping individual servers,
%% adding and removing them dynamically
%% The master is for book keeping all running servers and
%% to hold information about them.
So what do we find when we poke into iserve_server_sup?
Well, my eyes are too blurry to find out. But I’ll try to get back to this when the dust settles. Promise.
Back anon.
Note to wizards: corrections/comments welcomed.
Newbie Test: iserve – application resource file
April 3, 2009
March 30 Poking Around Erlang touched on iserve’s application resource file, iserve.app.
If you’re an Erlang newbie, it’s worth studying this file closely. Much can be gleaned about the application you’re setting out to understand.
At risk of boring wizards beyond tears, here is iserve.ap in all it’s glory:
{application, iserve,
[{description, "Web Server"},
{vsn, "%ISERVE_VSN%"},
{modules, [ iserve_sup,
iserve_app,
iserve_server,
iserve_socket
]},
{registered, [ iserve_sup]},
{applications, [kernel, stdlib, sasl]},
{mod, {iserve_app, []}},
{env, [{port, 8080}, {callback, iserve_test}]}]}.
Why is this file important and what does it tell us?
The Erlang app man page is a good place to go for answers.
Erlang/OTP conventions call for one application resource file for each application in the system. The file should be named Application.app, where Application is the name of the application. It should be located in the application’s ebin directory.
The application resource file is read by the application controller when an application is loaded/started. It is also used by functions in systools when generating start scripts.
Note that the structure of the iserve’s resource specification is a series of comma-delimited tuples, Each tuple is prefaced with an atom, italicized below.
I’d hoped to have decoder rings made up, but the following will have to do in the interim:
application (name of the application): iserve
description (one-line description of the application): Web Server
version (version of the application): “%ISERVE_VSN%” NOTE: instantiated elsewhere
modules (all modules introduced by the application): iserve_sup, iserve_app,
iserve_server, iserve_socket
registered (all names of registered processes started in this application): iserve_sup
applications (all applications which must be started before this application is allowed to be started): kernel, stdlib, sasl
mod (application callback module and start argument): iserve_app, []
env (configuration parameters used by the application): port, 8080; callback, iserve_test
So, now we know that among all the files in the iserve directories, we must pay closest attention to iserve_server and iserve_socket to understand functionality. We must start up kernel, stdlib, and sasl before we start iserve. To start iserve, we need to call iserve_sup.
Useful overview for one short file. And the good news is that you’ll find a similar file in the ebin directory of every Erlang/OTP application.
Newbie Test: iserve – poking deeper into the code
March 30, 2009
My March 20 post pointed out how Christian Sunesson’s fork of iserve incorporates OTP system principles.
This must have seemed obvious and a tad tedious to Erlang wizards, but it’s been useful for me as a newbie to stand the rather abstract statements of principle in the official Erlang OTP docs against an actual implementation.
In my experience, you can’t have too many examples to drive an abstract idea home. If I have one generic criticism of the otherwise admirable official Erlang documentation it would be just this: too few code-level examples.
I also found the comparison of iserve source against the OTP docs useful in another way: As a newbie poking into a non-trivial Erlang system, it’s a challenge to know where to start among the plethora of directories, modules, and supporting files as one strives to understand what’s going on.
An understanding of OTP conventions whittles down the challenge considerably.
So, today I’m poking a bit deeper into the mysteries of OTP and iserve. Then, in another post or two I’ll try to lay out my understanding of how iserve works and, maybe, point out a few interesting code phases and idioms that I’ve noticed along the way.
My usual caution: I’m a newbie. If I get something wrong feel free to scold me, but better, please help us rise to better understanding with detailed what and why.
Let’s look first at two files in the iserve src directory: iserve_sup.erl and iserve_server_sup.erl.
When you dive into OTP Design Principles, the first thing you learn is that the supervision tree is a basic concept in Erlang/OTP.
Since you can read as well as I, no need to go too deeply into it here other than to identify iserve_sup.erl and iserve_server_sup.erl as examples of callback functions that tell a more generic OTP supervisor module what to supervise and how. The clue? Note the *_sup.erl module names and the -behaviour(supervisor) directives in each of the modules.
If you open iserve_sup.erl you’ll note that the init/1 function starts and supervises two worker processes, iserve_server_sup.erl and iserve_master.erl.
With guidance from the OTP docs we can further decipher what’s going on:
Here’s specification of the first worker process:
Servers = {servers_sup,
{iserve_server_sup, start_link, [Supervisor]},
permanent, 2000, worker, [iserve_server_sup]},
- servers_sup is the id of the first worker process
- iserve_server_sup, start_link tells the supervisor how start the worker
- Supervisor … frankly, this puzzle me, perhaps you can clear it up for us
- permanent says that the child function should always be restarted
- the integer 2000 is a timeout value.
-
The OTP docs tells that: “An integer timeout value means that the supervisor tells the child process to terminate by calling exit(Child, shutdown) and then waits for an exit signal back. If no exit signal is received within the specified time, the child process is unconditionally terminated using exit(Child, kill). “
- worker tells the supervising process that the child function is a worker process
- iserve_server_sup is the name of the callback module
Here’s the other child process specified in iserver_sup.erl:
Master = {master,
{iserve_master, start_link, [iserve_server_sup]},
permanent, 2000, worker, [iserve_master]},
See if you can decode it. Now open iserver_server_sup.erl and see if the code doesn’t make more sense.
Now let’s look at iserve.app and iserve_app.erl.
The key to understanding these two files may also be found in the Erlang/OTP docs.
When you check it out, you’ll find that iserve_app.erl is an application callback module which specifies how to start and stop the application and iserve.app is an application resource file which specifies which modules the application consists of and the name of the callback module.
So, between the supervision and application files we have a fine road map for understanding the rest of the application.
But, enough for today. My bride will be home soon and it’s my night to bring up dinner.
Best to all.
Tidbits: Webmachine, Ngnix, and More
March 24, 2009
Webmachine
Thanks to alert correspondent Jamaal we’ve just learned that Justin Sheehy has released version 1.0 of Webmachine.
Justin positions Webmachine as “an application layer that adds HTTP semantic awareness on top of the excellent bit-pushing and HTTP syntax-management provided by mochiweb, and provides a simple and clean way to connect that to your application’s behavior.”
He further notes “From the way that Webmachine’s decision core works, it follows that Webmachine’s HTTP behavior is transactional. Each HTTP Request is fully received, and the resulting HTTP Response is then fully constructed before being returned. This means that while Webmachine is suitable for a great many Web applications it is not a good fit for an application that will gradually or continuously stream responses back to clients inside the context of a single HTTP Request.”
Jamaal is smitten by Webmachine, finds it easy to work with. He’s promised notes on his experiences to date; we’re eagerly looking forward to them.
I’m thinking about moving Webmachine up the list as a Newbie Test candidate, but first need to finish up explorations of iserve.
Erlang and Ngnix and ???
Nick Gerakines is experimenting with a C/C++ Ngnix module as a front-end to Erlang.
JLouse says “Pre-process the data in other languages and make them into erlang terms which can be read fast by erlang.”
And adds “… don’t get bitten by the mnesia bug, please. It is almost always the case that mnesia and ETS are the wrong way to go.”
As a Newbie, one the attractions of Erlang was the impression that I didn’t have to pile heterogeneous software environments atop one another to get a job done. But these writers, and others, suggest that Erlang is not up to my hopes and expectations.
So what gives? What’s a Newbie to make of this? Is Erlang:
-
1) Immature? Give it time and it’ll deliver on the promise.
2) Incomplete? Give it time and it’ll embrace ever more functionality.
3) Specialized? It is what is; can’t be all things to all people; live with it.
4) OK as is? These guys may have a point, but by and large it’s sour grapes.
Love to hear from the gray-beard wizard contingent on this topic.
Best Practices
While we’re on the subject of Nick Gerakines, bookmark his list of Erlang Library Best Practices.
Can’t tell you how much this Newbie appreciates words of wisdom from the wise.
Formatting Dates in Erlang
Here’s another one to bookmark… a handy little function for formatting dates.