Slave (Class)

In: lib/slave.rb
Parent: Object
Slave TopLevel

the Slave class encapsulates the work of setting up a drb server in another process.

Methods

fork   gen_psname   getval   getval   new   shutdown   trace  

Constants

DEFAULT_SOCKET_CREATION_ATTEMPTS = Integer(ENV['SLAVE_SOCKET_CREATION_ATTEMPTS'] || 42)
DEFAULT_PULSE_RATE = Float(ENV['SLAVE_PULSE_RATE'] || 8)
DEFAULT_DEBUG = (ENV['SLAVE_DEBUG'] ? true : false)

Attributes

debug  [R] 
debug  [RW]  if this is true and you are running from a terminal information is printed on STDERR
obj  [R] 
object  [R] 
pid  [R] 
ppid  [R] 
psname  [R] 
pulse_rate  [RW]  defined the rate of pinging in the Heartbeat object
pulse_rate  [R] 
socket  [R] 
socket_creation_attempts  [RW] 
uri  [R] 

Classes and Modules

Class Slave::Heartbeat

Public Class methods

just fork with out silly warnings

[Source]

    # File lib/slave.rb, line 47
47:       def fork &block
48: #--{{{
49:         v = $VERBOSE
50:         begin
51:           $VERBOSE = nil
52:           Process::fork &block
53:         ensure
54:         $VERBOSE = v
55:         end
56: #--}}}
57:       end

look up a value in an option hash failing back to class defaults

[Source]

    # File lib/slave.rb, line 39
39:       def getval key, opts = {}
40: #--{{{
41:         keys = [key, key.to_s, key.to_s.intern]
42:         keys.each{|k| return opts[k] if opts.has_key?(k)}
43:         send key rescue nil
44: #--}}}
45:       end

‘obj’ can be any object and ‘opts’ may contain the keys ‘socket_creation_attempts’, ‘pulse_rate’, ‘psname’, or ‘debug’

[Source]

     # File lib/slave.rb, line 73
 73:     def initialize obj, opts = {}
 74: #--{{{
 75:       @obj = obj
 76: 
 77:       @socket_creation_attempts = getval('socket_creation_attempts', opts)
 78:       @pulse_rate = getval('pulse_rate', opts)
 79:       @debug = getval('debug', opts)
 80:       @psname = getval('psname', opts) || gen_psname(@obj)
 81: 
 82:       trace{ "socket_creation_attempts <#{ @socket_creation_attempts }>" }
 83:       trace{ "pulse_rate <#{ @pulse_rate }>" }
 84:       trace{ "psname <#{ @psname }>" }
 85: 
 86:       @shutdown = false
 87: 
 88:       @heartbeat = Heartbeat::new @pulse_rate, @debug
 89:       @r, @w = IO::pipe
 90:     #
 91:     # child
 92:     #
 93:       unless((@pid = Slave::fork))
 94:         begin
 95:           $0 = @psname 
 96:           @pid = Process::pid
 97:           @ppid = Process::ppid
 98: 
 99:           @r.close
100:           @socket = nil
101:           @uri = nil
102: 
103:           tmpdir = Dir::tmpdir
104:           basename = File::basename @psname
105: 
106:           @socket_creation_attempts.times do |attempt|
107:             begin
108:               s = File::join(tmpdir, "#{ basename }_#{ attempt }")
109:               u = "drbunix://#{ s }"
110:               DRb::start_service u, obj 
111:               @socket = s
112:               @uri = u
113:               trace{ "child - socket <#{ @socket }>" }
114:               trace{ "child - uri <#{ @uri }>" }
115:               break
116:             rescue Errno::EADDRINUSE
117:               nil
118:             end
119:           end
120: 
121:           if @socket and @uri
122:             @heartbeat.start
123:             @w.write @socket 
124:             @w.close
125:             trap('SIGUSR2') do
126:               @heartbeat.stop rescue nil
127:               DBb::thread.kill rescue nil
128:               FileUtils::rm_f @socket rescue nil
129:               exit!
130:             end
131:             DRb::thread.join
132:           else
133:             @w.close
134:           end
135:         rescue => e
136:           trace{ %[#{ e.message } (#{ e.class })\n#{ e.backtrace.join "\n" }] }
137:         ensure
138:           exit!
139:         end
140:     #
141:     # parent 
142:     #
143:       else
144:         Process::detach @pid
145:         @w.close
146:         @socket = @r.read
147:         @r.close
148: 
149:         trace{ "parent - socket <#{ @socket }>" }
150: 
151:         if @socket and File::exist? @socket
152:           at_exit{ FileUtils::rm_f @socket }
153:           @uri = "drbunix://#{ socket }"
154:           trace{ "parent - uri <#{ @uri }>" }
155:           @heartbeat.start
156:         #
157:         # starting drb on localhost avoids dns lookups!
158:         #
159:           DRb::start_service('druby://localhost:0', nil) unless DRb::thread
160:           @object = DRbObject::new nil, @uri
161:         else
162:           raise "failed to find slave socket <#{ @socket }>"
163:         end
164:       end
165: #--}}}
166:     end

Public Instance methods

generate a default name to appear in ps/top

[Source]

     # File lib/slave.rb, line 179
179:     def gen_psname obj
180: #--{{{
181:       "#{ obj.class }_slave_of_#{ Process::pid }".downcase
182: #--}}}
183:     end

see docs for class.getval

[Source]

     # File lib/slave.rb, line 185
185:     def getval key, opts = {}
186: #--{{{
187:       self.class.getval key
188: #--}}}
189:     end

stops the heartbeat thread and kills the child process

[Source]

     # File lib/slave.rb, line 168
168:     def shutdown
169: #--{{{
170:       raise "already shutdown" if @shutdown
171:       @heartbeat.stop rescue nil
172:       Process::kill('SIGUSR2', @pid) rescue nil
173:       Process::kill('SIGTERM', @pid) rescue nil
174:       FileUtils::rm_f @socket
175:       @shutdown = true
176: #--}}}
177:     end

debugging output

[Source]

     # File lib/slave.rb, line 191
191:     def trace
192: #--{{{
193:       STDERR.puts(yield) if @debug and STDERR.tty?
194: #--}}}
195:     end

[Validate]