[erlang-questions] pool:pspawn and spawning at specific nodes
Austin Seipp
mad.one@REDACTED
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:
[austin@REDACTED 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)
(main@REDACTED)1> c(pingpong).
{ok,pingpong}
(main@REDACTED)2> pingpong:start().
nodes registered: ponger@REDACTED and pinger@REDACTED
registered output server
main@REDACTED: successfully registered global name 'pong'
Pong received ping
Ping received pong
ping finished
Pong finished
main@REDACTED: successfully registered global name 'ping'
ok
(main@REDACTED)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:
[austin@REDACTED 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)
(main@REDACTED)1> c(pingpong).
{ok,pingpong}
(main@REDACTED)2> pingpong:start().
nodes registered: ponger@REDACTED and pinger@REDACTED
registered output server
main@REDACTED: successfully registered global name 'pong'
main@REDACTED: successfully registered global name 'ping'
ok
(main@REDACTED)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
'filesystem@REDACTED' and another one called 'main@REDACTED' and have the
filesystem@REDACTED system take care of the processes that store info
into the filesystem, while main@REDACTED 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 main@REDACTED node with the
incoming connection code because pool:pspawn decided main@REDACTED 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