[erlang-questions] pool:pspawn and spawning at specific nodes

Austin Seipp <>
Tue Mar 6 04:52:17 CET 2007


Hi,

I've been working on a little toy erlang program to kill some time. It
is essentially a simple "Ping, pong" program (as seen in the erlang
documentation.) I decided to modify it so that it could do things like
scale itself appropriately (I use pool:start to automatically start
erlang systmes based on ~/.hosts.erlang) and automatically distribute
the 'Ping' and the 'Pong' processes amongst the slave nodes brought
up. Here is my code:

-module(pingpong).
-export([start/0,ping/1,pong/0,output_server/0]).

output_server() ->
   receive
       {format,{Str,Fmt}} ->
           io:fwrite(standard_io,"~s ~s~n",[Str,Fmt]),
           output_server()
   end.

ping(0) ->
   global:send(pongServer,finished),
   global:send(outServer,{format,{"ping finished",""}});

ping(N) ->
   global:send(pongServer,{ping,self()}),
   receive
       pong ->
           global:send(outServer,{format,{"Ping received pong",""}})
   end,
   pingpong:ping(N-1).

pong() ->
   receive
       finished ->
           global:send(outServer,{format,{"Pong finished",""}});
       {ping,Ping_PID} ->
           global:send(outServer,{format,{"Pong received ping",""}}),
           Ping_PID ! pong,
           pingpong:pong()
   end.

start() ->
   PongSrv = lists:nth(1,pool:start(ponger)),
   PingSrv = lists:nth(1,pool:start(pinger)),
   io:format("nodes registered: ~s and ~s~n",[PongSrv,PingSrv]),

   %register output server
   OutSrv_PID = spawn(pingpong,output_server,[]),
   case global:register_name(outServer,OutSrv_PID) of
       no ->
           io:format("could not register output server, exit~n"),
           pool:stop(),
           exit(output_srvr_reg_err);
       yes -> io:format("registered output server~n")
   end,

   %register pong server
   PongSrv_PID = pool:pspawn(pingpong,pong,[]),
   case global:register_name(pongServer,PongSrv_PID) of
       no ->
           io:format("could not register name globally: err~n"),
           pool:stop(),
           exit(global_name_reg_err);
       yes ->
           io:format("~s: successfully registered global name
'pong'~n",[node()])
   end,

   %register ping client
   PingSrv_PID = pool:pspawn(pingpong,ping,[1]),
   case global:register_name(pingServer,PingSrv_PID) of
       yes ->
            io:format("~s: successfully registered global name
'ping'~n",[node()]);
       no ->
           io:format("couldn't register name globally: err~n"),
           pool:stop(),
           exit(global_name_reg_err)
   end.

Here is the output:

[ erlang]$ erl -sname main
Erlang (BEAM) emulator version 5.5.3 [source] [async-threads:0] [hipe]
[kernel-poll:false]

Eshell V5.5.3  (abort with ^G)
()1> c(pingpong).
{ok,pingpong}
()2> pingpong:start().
nodes registered:  and 
registered output server
: successfully registered global name 'pong'
Pong received ping
Ping received pong
ping finished
Pong finished
: successfully registered global name 'ping'
ok
()3>

As you can see, it works fine. However, I wanted to spawn the two
seperate Ping and Pong enteties on nodes *at my discretion.*
pool:pspawn simply takes the system out of the pool with the lowest
load (expected) and starts the new process there. So I sought to see
if the regular spawn/4 BIF could spawn it on a node of my choice,
here's the start() and the way I changed it:



And here's the output now:

[ erlang]$ erl -sname main
Erlang (BEAM) emulator version 5.5.3 [source] [async-threads:0] [hipe]
[kernel-poll:false]

Eshell V5.5.3  (abort with ^G)
()1> c(pingpong).
{ok,pingpong}
()2> pingpong:start().
nodes registered:  and 
registered output server
: successfully registered global name 'pong'
: successfully registered global name 'ping'
ok
()3>


So my question really is: can you start processes on slave nodes you
bring up via pool:start() *explicitly* (that is, you specify on what
slave to bring the process up on) rather than letting pspawn decide,
or must you let pool:pspawn() care of it, or is there another
solution?
I wanted to see if I could write a small distributed system that
automatically scaled across available systems like this one did, and I
figure I could use pool:start(...) to give meaningful names to the
Erlang systems I brought up, and bring up a certain part of the whole
program on that node explicitly (for example, if you had a database
server written in erlang, you may want to start several nodes, say
'' and another one called '' and have the
 system take care of the processes that store info
into the filesystem, while  would handle incoming
connections. pool:pspawn chooses whatever system has the least load;
name is irrelivant, so I mean, it's not very logical to have the
filesystem processes executing on the  node with the
incoming connection code because pool:pspawn decided  had
a little less load. Please also note how many computers are actually
involved in this is irrelivant, I just want my processes spawning on
the slave nodes I specify, and not delegate it to pool:pspawn.)


Any recommendations? I suppose this setup would do, but it's not
exactly the ideal scenario here.
--
- Austin



More information about the erlang-questions mailing list