Slave-1.2.1


#1

SYNOPSIS

the Slave class forks a process and starts a drb server in the child
using
any object as the server. the process is detached so it is not
required
(nor possible) to wait on the child pid. a Heartbeat is set up
between the
parent and child processes so that the child will exit of the parent
exits
for any reason - preventing orphaned slaves from running
indefinitely. the
purpose of Slaves is to be able to easily set up a collection of
objects
communicating via drb protocols instead of having to use IPC.

typical usage:

 slave = Slave::new{ AnyObject.new }

 slave.object                  #=> handle on drb object
 slave.uri                     #=> uri of the drb object
 slave.socket                  #=> unix domain socket path for drb 

object
slave.psname #=> title shown in ps/top

 object = slave.object

 value = object.any_method     #=> use the object normally

slaves may be configured via the environment, the Slave class, or via
the
ctor for object itself. attributes which may be configured include

 * object : specify the slave object.  otherwise block value is 

used.
* socket_creation_attempts : specify how many attempts to create a
unix domain socket will be made
* debug : turn on some logging to STDERR
* psname : specify the name that will appear in ‘top’ ($0)
* at_exit : specify a lambda to be called in the parent when the
child dies
* dumped : specify that the slave object should not be
DRbUndumped (default is DRbUndumped)
* threadsafe : wrap the slave object with ThreadSafe to implement
gross thread safety

URIS

http://rubyforge.org/projects/codeforpeople/
http://codeforpeople.com/lib/ruby/slave

HISTORY

1.2.1:
- jruby/ThreadSafe patches from skaar and ez. using slave.rb with
jruby,
how cool is that!?

SAMPLES

<========< samples/a.rb >========>

~ > cat samples/a.rb

 require 'slave'
 #
 # simple usage is simply to stand up a server object as a slave. 

you do not
# need to wait for the server, join it, etc. it will die when the
parent
# process dies - even under ‘kill -9’ conditions
#
class Server
def add_two n
n + 2
end
end

   slave = Slave.new :object => Server.new

   server = slave.object
   p server.add_two(40) #=> 42

   slave.shutdown

~ > ruby samples/a.rb

 42

<========< samples/b.rb >========>

~ > cat samples/b.rb

 require 'slave'
 #
 # if certain operations need to take place in the child only a 

block can be
# used
#
class Server
def connect_to_db
“we only want to do this in the child process!”
@connection = :postgresql
end
attr :connection
end

   slave = Slave.new('object' => Server.new){|s| s.connect_to_db}

   server = slave.object

   p server.connection  #=> :postgresql
 #
 # errors in the child are detected and raised in the parent
 #
   slave = Slave.new('object' => Server.new){|s| s.typo} #=> raises 

an error!

~ > ruby samples/b.rb

 :postgresql
 samples/b.rb:22: undefined method `typo' for #<Server:0xb756ed18> 

(NoMethodError)
from ./lib/slave.rb:369:in []' from ./lib/slave.rb:369:ininitialize’
from samples/b.rb:22:in `new’
from samples/b.rb:22

<========< samples/c.rb >========>

~ > cat samples/c.rb

 require 'slave'
 #
 # if no slave object is given the block itself is used to contruct 

it
#
class Server
def initialize
“this is run only in the child”
@pid = Process.pid
end
attr ‘pid’
end

   slave = Slave.new{ Server.new }
   server = slave.object

   p Process.pid
   p server.pid # not going to be the same as parents!
 #
 # errors are still detected though
 #
   slave = Slave.new{ fubar } # raises error in parent

~ > ruby samples/c.rb

 7971
 7972
 samples/c.rb:21: undefined local variable or method `fubar' for 

main:Object (NameError)
from ./lib/slave.rb:361:in call' from ./lib/slave.rb:361:ininitialize’
from samples/c.rb:21:in `new’
from samples/c.rb:21

<========< samples/d.rb >========>

~ > cat samples/d.rb

 require 'slave'
 #
 # at_exit hanlders are handled correctly in both child and parent
 #
   at_exit{ p 'parent' }
   slave = Slave.new{ at_exit{ p 'child' };  'the server is this 

string’ }
#
# this will print ‘child’, then ‘parent’
#

~ > ruby samples/d.rb

 "child"
 "parent"

<========< samples/e.rb >========>

~ > cat samples/e.rb

 require 'slave'
 #
 # slaves never outlive their parent.  if the parent exits, even 

under kill -9,
# the child will die.
#
slave = Slave.new{ at_exit{ p ‘child’ }; ‘the server is this
string’ }

   Process.kill brutal=9, the_parent_pid=Process.pid
 #
 # even though parent dies a nasty death the child will still print 

‘child’
#

~ > ruby samples/e.rb

 "child"

<========< samples/f.rb >========>

~ > cat samples/f.rb

 require 'slave'
 #
 # slaves created previously are visible to newly created slaves - 

in this
# example the child process of slave_a communicates directly with
the child
# process of slave_a
#
slave_a = Slave.new{ Array.new }
slave_b = Slave.new{ slave_a.object }

   a, b = slave_b.object, slave_a.object

   b << 42
   puts a #=> 42

~ > ruby samples/f.rb

 42

<========< samples/g.rb >========>

~ > cat samples/g.rb

 require 'slave'
 #
 # Slave.object can used when you want to construct an object in 

another
# process. in otherwords you want to fork a process and retrieve a
single
# returned object from that process as opposed to setting up a
server.
#
this = Process.pid
that = Slave.object{ Process.pid }

   p 'this' => this, 'that' => that

 #
 # any object can be returned and it can be returned asychronously 

via a thread
#
thread = Slave.object(:async => true){ sleep 2 and [ Process.pid,
Time.now ] }
this = [ Process.pid, Time.now ]
that = thread.value

   p 'this' => this, 'that' => that

~ > ruby samples/g.rb

 {"that"=>7990, "this"=>7989}
 {"that"=>[7991, Fri, Apr 27 2007 16:38:30 -0600], "this"=>[7989, 

Fri, Apr 27 2007 16:38:28 -0600]}

enjoy.

-a


#2

Ara.T.Howard wrote:

SYNOPSIS

the Slave class forks a process and starts a drb server in the child
using
any object as the server. the process is detached so it is not
required
(nor possible) to wait on the child pid. a Heartbeat is set up
between the
parent and child processes so that the child will exit of the parent
exits
for any reason - preventing orphaned slaves from running
indefinitely. the
purpose of Slaves is to be able to easily set up a collection of
objects
communicating via drb protocols instead of having to use IPC.

Is this being maintained any more? Should I be using some other module
for the same functionality in the future? It’s a nice tool to use, but
I’m going insane trying to debug issues and warnings with the code in my
Recursive Parallel directory descent tool.

Thanks,
John