README

Path: README
Last Update: Fri Oct 13 13:23:22 MDT 2006
TopLevel

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/
  https://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<[email protected]>.  the impl dropped opts
      delgating to the class method from the instance one.

  0.2.0:
    incorporated joel vanderWerf's patch such that, if no object is passed the
    block is used to create one ONLY in the child.  this avoids having a copy
    in both parent and child is that needs to be avoided due to, for instance,
    resource consumption.

  0.0.1:
    - patch from Logan Capaldo adds block form to slave new, block is run in the
      child

    - added a few more samples/*

    - added Slave#wait

    - added status information to slaves

    - added close-on-exec flag to pipes in parent process

  0.0.0:
    - initial version

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

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

[Validate]