[newbie] accept()-ing process under supervision (was:Erlangish way of Iterator pattern)

Joe Armstrong (AL/EAB) joe.armstrong@REDACTED
Wed Jan 26 16:07:29 CET 2005


Tricky - there is a spectrum of answers here:

"make sure that it is always listening" could mean lot's of different things:

	1) Is the listening process (ie the process which evaluates tcp_accept)
                still alive?
	2) Is the listening process responsive?
	    ie is it accepting connections and doing what it is supposed to do?

In my example tcp_server might happily accept connections and spawn a new handler
per connection - but these handlers might deadlock, or go into infinite loops or something and not respond as
expected (Now I don't mean here that the handlers *crash* - because crashes will be detected and the
socket will be closed) - it's just that they don't work properly.

Detecting 1) is trivial (just link to the process). 2) requires some kind of end-to-end confirmation
ie a program *outside* Erlang which periodically asks the server to prove that it running. 
Say ask it what factorial 42 is once every minute.

<<to be really safe - the probing program should be on a *different* processor -
    because of "Joe's law"
	
	+------------+
	| Joe's law |
	+-----------------------------------------+
	|  To do fault-tolerant computations |
            | you need at least 2 computers      |
	+-----------------------------------------+

     Obviously :-)
   
>>


An easy solution (somewhere between 1 and 2 here) can be to use "on-exit" defined thus:

on_exit(Pid, Fun) ->
         spawn_fun(fun() -> 
                          process_flag(trap_exit, true),
                          link(Pid),
                          receive
                              {'EXIT', Pid, Why} ->
                                  Fun(Why)
                          end
                   end).

You can use on_exit to restart a function if it fails.

[almost] like this:

keep_alive(Fun) ->
	Pid = spawn(fun() -> Fun() end),
	on_exit(Pid, 
		fun({'Exit', normal} ->
			true;
		       {'EXIT', Other} ->
			%% restart it
			keep_alive(Fun)
		end).

Cheers

/Joe

[almost] - the code above is incorrect - and is merely to illustrate the idea -
why is it incorrect? (ten brownie points for the first correct explanation of the error :-)










> -----Original Message-----
> From: owner-erlang-questions@REDACTED 
> [mailto:owner-erlang-questions@REDACTED]On Behalf Of Gaspar 
> Chilingarov
> Sent: den 26 januari 2005 12:07
> To: erlang-questions@REDACTED
> Subject: Re: [newbie] accept()-ing process under supervision 
> (was:Erlangish way of Iterator pattern)
> 
> 
> Yeah, i know, you have some tasty things on your pages :)
> 
> but i wish to run process which does gen_tcp:accept under 
> supervision -- 
> just to be sure that it always listening. processes which serve each 
> connections are out of my interest (for now) -- they can 
> crash when they 
> want :)
> 
> 
> Joe Armstrong (AL/EAB) wrote:
> > To solve problems like this I almost always use a module 
> called tcp_server which is
> > available at
> > 
> > 	http://www.sics.se/~joe/tutorials/web_server/tcp_server.erl
> > 
> > To use it call:
> > 
> > 	tcp_server:start(Port, Fun, Max)
> > 
> > This starts a server which listens to Port up to Max 
> simultaneous connections on Port are allowed.
> >  
> > The *first* time a connection is made to Port Then 
> Fun(Socket) is called. 
> > Thereafter messages to the socket result in messages to the handler.
> > 
> > A typical server is usually written like this:
> > 
> >     start_server(Port) ->    
> >           S = self(),  
> >           process_flag(trap_exit, true), 
> >           tcp_server:start_raw_server(Port, 
> >  				fun(Socket) -> 
> input_handler(Socket, S) end, 
> > 				15,
> >                              0)
> >          loop().
> > 
> > The loop() process is a central controller that all 
> processes can use to synchronize amongst themselves if 
> necessary It ends up as the variable "Controller" in the input_handler
> > 
> > A typical server is written like this:
> > 
> >   input_handler(Socket, Controller) ->
> >     receive
> > 	{tcp, Socket, Bin} ->
> > 	    ...
> > 	    gen_tcp:send(Socket, ...)
> >  	{tcp_closed, Socket} ->
> > 
> >  	Any ->
> > 	    ... 
> >      end.
> > 
> > tcp_server can be used to build many different things. For 
> example a web server or wiki system.
> > 
> > If you want to see how to make a web server using 
> tcp_server read my second "spitting in the dust tutorial" on how to
> > make a web server.
> > 
> > This is at
> > 
> > 	http://www.sics.se/~joe/tutorials/web_server/web_server.html
> > 
> > This has all the code for a simple web server - the web 
> server itself is split into a http parser (222 lines of code)
> > a server (104 lines) and the tcp_server (175) lines. 
> > 
> > I'll show you the code for the web server - it's like this:
> > 
> > server(Client, Master) ->
> >     receive
> > 	{Client, closed} ->
> > 	    true;
> > 	{Client, Request} ->
> > 	    Response = generate_response(Request),
> > 	    Client ! {self(), Response},
> > 	    server(Client, Master)
> >     after 5000 ->
> > 	    true
> >     end.
> > 
> > That's all :-)
> > 
> > The structure used in the web server provides a useful 
> model of how to build these type of things.  It has
> > 
> > 	- a connection handler (tcp_server) which manages tcp sessions
> > 	- a device driver that parses HTTP messages and turns 
> them into Erlang messages
> > 	- a pure Erlang server
> > 
> > The general philosophy is "pretend that all things in the 
> outside world are Erlang processes" - thus to program a web
> > server we model the browser as an Erlang process - it sends 
> a {get, File} message to the server. The job of the
> > connection handler and device driver is to take the HTTP 
> protocol message and turn them into Erlang terms.
> > Having done so, writing the server is a doodle.
> > 
> >   Cheers
> > 
> > /Joe
> > 
> > 
> > 
> > 
> >>-----Original Message-----
> >>From: owner-erlang-questions@REDACTED 
> >>[mailto:owner-erlang-questions@REDACTED]On Behalf Of Gaspar 
> >>Chilingarov
> >>Sent: den 25 januari 2005 15:20
> >>To: erlang-questions@REDACTED
> >>Subject: [newbie] Erlangish way of Iterator pattern
> >>
> >>
> >>Hello!
> >>
> >>I'm beginning to program in erlang and hit the following problem.
> >>in mainstream language i will do the following -- create 
> >>Iterator class 
> >>to read data from socket or file
> >>i.e. class with Open/GetNext functions. Open should just do 
> >>all work for 
> >>preparing data source and GetNext will return lines of data or 
> >>EOF(freeing resources when reaching EOF).
> >>
> >>
> >>what i have in erlang -- i have erlang process, which can 
> accept data 
> >>messages and eof messages and do processing. another process hangs 
> >>around, waiting for TCP connection and feeding first process 
> >>with data 
> >>read from TCP. in the same time i have shell script which 
> runs once a 
> >>minute and feeds data from some file(or piped command line) 
> >>to TCP port.
> >>
> >>now i want to get rid of shell script, but i wish to have separate 
> >>module which will do this -- i.e. 1. running periodically external 
> >>command, 2. feeding to another process.
> >>
> >>are there any idioms in Erlang for this or it should be 
> >>implemented in 
> >>straight way -- i.e. just another process sitting there and 
> >>doing it's 
> >>job -- file reading/parsing/feeding to another process ?
> >>
> >>
> >>
> >>-- 
> >>Gaspar Chilingarov
> >>System Administrator
> >>
> >>t +3749 419763
> >>w www.web.am
> >>e nm@REDACTED
> >>
> > 
> > 
> 
> 
> -- 
> Gaspar Chilingarov
> System Administrator
> 
> t +3749 419763
> w www.web.am
> e nm@REDACTED
> 



More information about the erlang-questions mailing list