Class: Pitchfork::Worker
- Inherits:
-
Object
- Object
- Pitchfork::Worker
- Defined in:
- lib/pitchfork/worker.rb
Overview
This class and its members can be considered a stable interface and will not change in a backwards-incompatible fashion between releases of pitchfork. Knowledge of this class is generally not not needed for most users of pitchfork.
Some users may want to access it in the after_worker_fork/after_mold_fork hooks. See the Pitchfork::Configurator RDoc for examples.
Constant Summary collapse
- EXIT_SIGNALS =
:stopdoc:
[:QUIT, :TERM]
Instance Attribute Summary collapse
-
#generation ⇒ Object
Returns the value of attribute generation.
-
#master ⇒ Object
Returns the value of attribute master.
-
#nr ⇒ Object
Returns the value of attribute nr.
-
#pid ⇒ Object
Returns the value of attribute pid.
-
#requests_count ⇒ Object
readonly
Returns the value of attribute requests_count.
Instance Method Summary collapse
-
#==(other) ⇒ Object
worker objects may be compared to just plain Integers.
-
#accept_nonblock(exception: nil) ⇒ Object
this only runs when the Rack app.call is not running act like a listener.
- #after_fork_in_child ⇒ Object
-
#close ⇒ Object
called in both the master (reaping worker) and worker (SIGQUIT handler).
- #create_socketpair! ⇒ Object
-
#deadline ⇒ Object
called in the master process.
-
#deadline=(value) ⇒ Object
called in the worker process.
- #exiting? ⇒ Boolean
-
#fake_sig(sig) ⇒ Object
call a signal handler immediately without triggering EINTR We do not use the more obvious Process.kill(sig, $$) here since that signal delivery may be deferred.
- #finish_promotion(control_socket) ⇒ Object
- #hard_kill(sig) ⇒ Object
- #increment_requests_count(by = 1) ⇒ Object
-
#initialize(nr, pid: nil, generation: 0) ⇒ Worker
constructor
A new instance of Worker.
- #meminfo ⇒ Object
- #mold? ⇒ Boolean
- #outdated? ⇒ Boolean
- #pending? ⇒ Boolean
- #promote(generation) ⇒ Object
- #promote!(timeout) ⇒ Object
- #promoted!(timeout) ⇒ Object
-
#quit ⇒ Object
master fakes SIGQUIT using this.
- #refresh ⇒ Object
- #register_to_master(control_socket) ⇒ Object
- #reset ⇒ Object
-
#soft_kill(sig) ⇒ Object
master sends fake signals to children.
- #spawn_worker(new_worker) ⇒ Object
- #start_promotion(control_socket) ⇒ Object
-
#to_io ⇒ Object
IO.select-compatible.
- #update(message) ⇒ Object
- #update_deadline(timeout) ⇒ Object
Constructor Details
#initialize(nr, pid: nil, generation: 0) ⇒ Worker
Returns a new instance of Worker.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/pitchfork/worker.rb', line 19 def initialize(nr, pid: nil, generation: 0) @nr = nr @pid = pid @generation = generation @mold = false @to_io = @master = nil @exiting = false @requests_count = 0 if nr @deadline_drop = SharedMemory.worker_deadline(nr) self.deadline = 0 else promoted!(nil) end end |
Instance Attribute Details
#generation ⇒ Object
Returns the value of attribute generation.
16 17 18 |
# File 'lib/pitchfork/worker.rb', line 16 def generation @generation end |
#master ⇒ Object
Returns the value of attribute master.
17 18 19 |
# File 'lib/pitchfork/worker.rb', line 17 def master @master end |
#nr ⇒ Object
Returns the value of attribute nr.
16 17 18 |
# File 'lib/pitchfork/worker.rb', line 16 def nr @nr end |
#pid ⇒ Object
Returns the value of attribute pid.
16 17 18 |
# File 'lib/pitchfork/worker.rb', line 16 def pid @pid end |
#requests_count ⇒ Object (readonly)
Returns the value of attribute requests_count.
17 18 19 |
# File 'lib/pitchfork/worker.rb', line 17 def requests_count @requests_count end |
Instance Method Details
#==(other) ⇒ Object
worker objects may be compared to just plain Integers
180 181 182 |
# File 'lib/pitchfork/worker.rb', line 180 def ==(other) # :nodoc: super || (!@nr.nil? && @nr == other) end |
#accept_nonblock(exception: nil) ⇒ Object
this only runs when the Rack app.call is not running act like a listener
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/pitchfork/worker.rb', line 157 def accept_nonblock(exception: nil) # :nodoc: loop do case buf = @to_io.recvmsg_nonblock(exception: false) when :wait_readable # keep waiting return false when nil # EOF master died, but we are at a safe place to exit fake_sig(:QUIT) return false when Message::SoftKill # trigger the signal handler fake_sig(buf.signum) # keep looping, more signals may be queued when Message return buf else raise TypeError, "Unexpected recvmsg_nonblock returns: #{buf.inspect}" end end # loop, as multiple signals may be sent rescue Errno::ECONNRESET nil end |
#after_fork_in_child ⇒ Object
217 218 219 |
# File 'lib/pitchfork/worker.rb', line 217 def after_fork_in_child @master&.close end |
#close ⇒ Object
called in both the master (reaping worker) and worker (SIGQUIT handler)
207 208 209 210 211 |
# File 'lib/pitchfork/worker.rb', line 207 def close # :nodoc: self.deadline = 0 @master.close if @master @to_io.close if @to_io end |
#create_socketpair! ⇒ Object
213 214 215 |
# File 'lib/pitchfork/worker.rb', line 213 def create_socketpair! @to_io, @master = Info.keep_ios(Pitchfork.socketpair) end |
#deadline ⇒ Object
called in the master process
194 195 196 |
# File 'lib/pitchfork/worker.rb', line 194 def deadline # :nodoc: @deadline_drop.value end |
#deadline=(value) ⇒ Object
called in the worker process
189 190 191 |
# File 'lib/pitchfork/worker.rb', line 189 def deadline=(value) # :nodoc: @deadline_drop.value = value end |
#exiting? ⇒ Boolean
43 44 45 |
# File 'lib/pitchfork/worker.rb', line 43 def exiting? @exiting end |
#fake_sig(sig) ⇒ Object
call a signal handler immediately without triggering EINTR We do not use the more obvious Process.kill(sig, $$) here since that signal delivery may be deferred. We want to avoid signal delivery while the Rack app.call is running because some database drivers (e.g. ruby-pg) may cancel pending requests.
132 133 134 135 136 137 |
# File 'lib/pitchfork/worker.rb', line 132 def fake_sig(sig) # :nodoc: old_cb = trap(sig, "IGNORE") old_cb.call ensure trap(sig, old_cb) end |
#finish_promotion(control_socket) ⇒ Object
82 83 84 85 86 87 |
# File 'lib/pitchfork/worker.rb', line 82 def finish_promotion(control_socket) = Message::MoldReady.new(@nr, @pid, generation) control_socket.sendmsg() SharedMemory.current_generation = @generation @deadline_drop = SharedMemory.mold_deadline end |
#hard_kill(sig) ⇒ Object
151 152 153 |
# File 'lib/pitchfork/worker.rb', line 151 def hard_kill(sig) Process.kill(sig, pid) end |
#increment_requests_count(by = 1) ⇒ Object
202 203 204 |
# File 'lib/pitchfork/worker.rb', line 202 def increment_requests_count(by = 1) @requests_count += by end |
#meminfo ⇒ Object
35 36 37 |
# File 'lib/pitchfork/worker.rb', line 35 def meminfo @meminfo ||= MemInfo.new(pid) if pid end |
#mold? ⇒ Boolean
110 111 112 |
# File 'lib/pitchfork/worker.rb', line 110 def mold? @mold end |
#outdated? ⇒ Boolean
51 52 53 |
# File 'lib/pitchfork/worker.rb', line 51 def outdated? SharedMemory.current_generation > @generation end |
#pending? ⇒ Boolean
47 48 49 |
# File 'lib/pitchfork/worker.rb', line 47 def pending? @master.nil? end |
#promote(generation) ⇒ Object
89 90 91 |
# File 'lib/pitchfork/worker.rb', line 89 def promote(generation) (Message::PromoteWorker.new(generation)) end |
#promote!(timeout) ⇒ Object
97 98 99 100 |
# File 'lib/pitchfork/worker.rb', line 97 def promote!(timeout) @generation += 1 promoted!(timeout) end |
#promoted!(timeout) ⇒ Object
102 103 104 105 106 107 108 |
# File 'lib/pitchfork/worker.rb', line 102 def promoted!(timeout) @mold = true @nr = nil @deadline_drop = SharedMemory.mold_promotion_deadline update_deadline(timeout) if timeout self end |
#quit ⇒ Object
master fakes SIGQUIT using this
119 120 121 |
# File 'lib/pitchfork/worker.rb', line 119 def quit # :nodoc: @master = @master.close if @master end |
#refresh ⇒ Object
39 40 41 |
# File 'lib/pitchfork/worker.rb', line 39 def refresh meminfo&.update end |
#register_to_master(control_socket) ⇒ Object
68 69 70 71 72 73 |
# File 'lib/pitchfork/worker.rb', line 68 def register_to_master(control_socket) create_socketpair! = Message::WorkerSpawned.new(@nr, @pid, generation, @master) control_socket.sendmsg() @master.close end |
#reset ⇒ Object
198 199 200 |
# File 'lib/pitchfork/worker.rb', line 198 def reset @requests_count = 0 end |
#soft_kill(sig) ⇒ Object
master sends fake signals to children
140 141 142 143 144 145 146 147 148 149 |
# File 'lib/pitchfork/worker.rb', line 140 def soft_kill(sig) # :nodoc: signum = Signal.list[sig.to_s] or raise ArgumentError, "BUG: bad signal: #{sig.inspect}" # Do not care in the odd case the buffer is full, here. success = (Message::SoftKill.new(signum)) if success && EXIT_SIGNALS.include?(sig) @exiting = true end success end |
#spawn_worker(new_worker) ⇒ Object
93 94 95 |
# File 'lib/pitchfork/worker.rb', line 93 def spawn_worker(new_worker) (Message::SpawnWorker.new(new_worker.nr)) end |
#start_promotion(control_socket) ⇒ Object
75 76 77 78 79 80 |
# File 'lib/pitchfork/worker.rb', line 75 def start_promotion(control_socket) create_socketpair! = Message::MoldSpawned.new(@nr, @pid, generation, @master) control_socket.sendmsg() @master.close end |
#to_io ⇒ Object
IO.select-compatible
114 115 116 |
# File 'lib/pitchfork/worker.rb', line 114 def to_io # IO.select-compatible @to_io.to_io end |
#update(message) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/pitchfork/worker.rb', line 55 def update() .class.members.each do |member| send("#{member}=", .public_send(member)) end case when Message::MoldSpawned @deadline_drop = SharedMemory.mold_promotion_deadline when Message::MoldReady @deadline_drop = SharedMemory.mold_deadline end end |