[ANN] slave-1.0.0

** PLEASE NOTE THAT THIS IS A DEVELOPMENTAL RELEASE **

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:

     obj = AnyClass::new

     slave = Slave::new 'object' => obj

     p slave.object # handle on drb object
     p slave.uri # uri of the drb object
     p slave.socket # unix domain socket path for drb object
     p slave.psname # title shown in ps/top

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

     * socket_creation_attempts
     * pulse_rate
     * psname
     * debug
     * dumped

URIS

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

HISTORY

   THIS RELEASE IS !! NOT !! BACKWARD COMPATIBLE. NOTE NEW CTOR SYNTAX.

   1.0.0:

     - detach method also sets up at_exit handler. extra protection from
       zombies.

     - ezra zygmuntowicz asked for a feature whereby a parent could be notified
       when a child exited. obviously such a mechanism should be both async
       and sync. to accomplish this the wait method was extended to support a
       callback with is either sync or async

         slave = Server.new{ Server.new }

         slave.wait and puts 'this is sync!'

         slave.wait(:non_block=>true){ 'this is async!' }

     - patch to getval from skaar<skaar@waste.org>. the impl dropped opts
       delgating to the class method from the instance one.

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

   ~ > 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
     ./lib/slave.rb:276:in `initialize': undefined method `typo' for #<Server:0xb7573350> (NoMethodError)
       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

     12244
     12245
     ./lib/slave.rb:276:in `initialize': undefined local variable or method `fubar' for main:Object (NameError)
       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"

enjoy.

-a
--
my religion is very simple. my religion is kindness. -- the dalai lama

Hi Ara-

<snip>

    - detach method also sets up at_exit handler. extra protection from
      zombies.

    - ezra zygmuntowicz asked for a feature whereby a parent could be notified
      when a child exited. obviously such a mechanism should be both async
      and sync. to accomplish this the wait method was extended to support a
      callback with is either sync or async

        slave = Server.new{ Server.new }

        slave.wait and puts 'this is sync!'

        slave.wait(:non_block=>true){ 'this is async!' }

Awesome thanks Ara!

  <========< 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

  This part if killer too. Very nice to be able to run the block in the child! I am getting a ton of use out of Slave. Thanks for the killer library.

Cheers-
-Ezra

···

On Oct 13, 2006, at 12:30 PM, ara.t.howard@noaa.gov wrote:

Awesome thanks Ara!

no prob - it was a good idea

  This part if killer too. Very nice to be able to run the block in the child! I am getting a ton of use out of Slave. Thanks for the killer library.

great! test this one out though - i made quite few small changes, and you
know how that goes!

let me know what you find...

have a good weekend.

-a

···

On Sat, 14 Oct 2006, Ezra Zygmuntowicz wrote:
--
my religion is very simple. my religion is kindness. -- the dalai lama