Class | Slave::LifeLine |
In: |
lib/slave.rb
|
Parent: | Object |
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.
FDS | = | ThreadSafeHash.new |
DELEGATED | = | %w( puts gets read write close flush each ) |
"cut" | -> | "release" |
# 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
# 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
# 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
# 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
# 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
# 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