Class Slave::LifeLine
In: lib/slave.rb
Parent: Object
Slave dot/f_1.jpg

the LifeLine class is used to communitacte between child and parent processes and to prevent child processes from ever becoming zombies or otherwise abandoned by their parents. the basic concept is that a socket pair is setup between child and parent. the child process, because it is a Slave, sets up a handler such that, should it‘s socket ever grow stale, will exit the process. this class replaces the HeartBeat class from previous Slave versions.

Methods

Constants

FDS = ThreadSafeHash.new
DELEGATED = %w( puts gets read write close flush each )

External Aliases

"cut" -> "release"

Public Class methods

[Source]

     # File lib/slave.rb, line 171
171:       def initialize
172:         @pair = Socket.pair Socket::AF_UNIX, Socket::SOCK_STREAM, 0
173:         @owner = Process.pid
174:         @pid = nil
175:         @socket = nil
176:         @object_id = object_id
177: 
178:         @fds = @pair.map{|s| s.fileno}
179:         oid, fds = @object_id, @fds
180:         FDS[oid] = fds 
181:         ObjectSpace.define_finalizer(self){ FDS.delete oid } 
182:       end

Public Instance methods

[Source]

     # File lib/slave.rb, line 197
197:       def catch *ignored
198:         raise if owner?
199:         @pair[0].close
200:         @pair[0] = nil
201:         @pid = Process.pid
202:         @socket = @pair[-1]
203:         @socket.sync = true
204:         close_unused_sockets_after_forking
205:       end

[Source]

     # File lib/slave.rb, line 265
265:       def cling &b
266:         on_cut{ begin; b.call if b; ensure; Kernel.exit; end }.join
267:       end

[Source]

     # File lib/slave.rb, line 207
207:       def close_unused_sockets_after_forking
208:         begin
209:           to_delete = []
210:           begin
211:             FDS.each do |oid, fds|
212:               next if oid == @object_id
213:               begin
214:                 IO.for_fd(fds.first).close
215:               rescue Exception => e
216:                 STDERR.puts "#{ e.message } (#{ e.class })\n#{ e.backtrace.join 10.chr }"
217:               ensure
218:                 to_delete << oid
219:               end
220:             end
221:           ensure
222:             FDS.ex{ to_delete.each{|oid| FDS.delete oid rescue 42} }
223:           end
224:           GC.start
225:         rescue Exception => e
226:           42
227:         end
228:       end

[Source]

     # File lib/slave.rb, line 230
230:       def cut
231:         raise unless owner?
232:         raise unless @socket
233:         @socket.close rescue nil
234:         FDS.delete object_id
235:       end

[Source]

     # File lib/slave.rb, line 250
250:       def on_cut &b
251:         at_exit{ begin; b.call; ensure; b = nil; end if b}
252:         Thread.new(Thread.current){|current|
253:           Thread.current.abort_on_exception = true
254:           begin
255:             each{|*a|}
256:           rescue Exception
257:             current.raise $!
258:             42
259:           ensure
260:             begin; b.call; ensure; b = nil; end if b
261:           end
262:         }
263:       end

[Source]

     # File lib/slave.rb, line 184
184:       def owner?
185:         Process.pid == @owner
186:       end

[Source]

     # File lib/slave.rb, line 188
188:       def throw *ignored
189:         raise unless owner?
190:         @pair[-1].close
191:         @pair[-1] = nil
192:         @pid = Process.pid
193:         @socket = @pair[0]
194:         @socket.sync = true
195:       end

[Validate]