Module: Einhorn::Worker
- Defined in:
- lib/einhorn/worker.rb
Defined Under Namespace
Classes: WorkerError
Class Method Summary collapse
- .ack(*args) ⇒ Object
-
.ack!(discovery = :env, arg = nil) ⇒ Object
Call this once your app is up and running in a good state.
-
.einhorn_child_index ⇒ Object
Returns the index of this Einhorn child process.
- .einhorn_fd(n) ⇒ Object
- .einhorn_fd_count ⇒ Object
- .ensure_worker! ⇒ Object
-
.graceful_shutdown(&blk) ⇒ Object
Call this to handle graceful shutdown requests to your app.
- .is_worker? ⇒ Boolean
-
.ping!(request_id, discovery = :env, arg = nil) ⇒ Object
Call this to indicate your child process is up and in a healthy state.
- .socket(number = nil) ⇒ Object
- .socket!(number = nil) ⇒ Object
Class Method Details
.ack(*args) ⇒ Object
29 30 31 32 33 34 |
# File 'lib/einhorn/worker.rb', line 29 def self.ack(*args) begin ack!(*args) rescue WorkerError end end |
.ack!(discovery = :env, arg = nil) ⇒ Object
Call this once your app is up and running in a good state. Arguments:
@discovery: How to discover the master process’s command socket.
:env: Discover the path from ENV['EINHORN_SOCK_PATH']
:fd: Just use the file descriptor in ENV['EINHORN_SOCK_FD'].
Must run the master with the -g flag. This is mostly
useful if you don't have a nice library like Einhorn::Worker.
Then @arg being true causes the FD to be left open after ACK;
otherwise it is closed.
:direct: Provide the path to the command socket in @arg.
TODO: add a :fileno option? Easy to implement; not sure if it’d be useful for anything. Maybe if it’s always fd 3, because then the user wouldn’t have to provide an arg.
68 69 70 71 72 |
# File 'lib/einhorn/worker.rb', line 68 def self.ack!(discovery=:env, arg=nil) handle_command_socket(discovery, arg) do |client| client.send_command('command' => 'worker:ack', 'pid' => $$) end end |
.einhorn_child_index ⇒ Object
Returns the index of this Einhorn child process.
If an Einhorn master has N children, this will be an integer in the range [0,N), and no two workers running concurrently will ever have the same index.
Returns nil if not running in Einhorn, or running on a version of Einhorn that does not support indexing children.
44 45 46 47 48 49 50 51 |
# File 'lib/einhorn/worker.rb', line 44 def self.einhorn_child_index index = ENV['EINHORN_CHILD_INDEX'] if index.nil? || index !~ /\A \d+ \z/x index else index.to_i end end |
.einhorn_fd(n) ⇒ Object
116 117 118 119 120 121 |
# File 'lib/einhorn/worker.rb', line 116 def self.einhorn_fd(n) unless raw_fd = ENV["EINHORN_FD_#{n}"] return nil end Integer(raw_fd) end |
.einhorn_fd_count ⇒ Object
123 124 125 126 127 128 |
# File 'lib/einhorn/worker.rb', line 123 def self.einhorn_fd_count unless raw_count = ENV['EINHORN_FD_COUNT'] return 0 end Integer(raw_count) end |
.ensure_worker! ⇒ Object
18 19 20 21 22 23 24 25 26 27 |
# File 'lib/einhorn/worker.rb', line 18 def self.ensure_worker! # Make sure that EINHORN_MASTER_PID is my parent if ppid_s = ENV['EINHORN_MASTER_PID'] ppid = ppid_s.to_i raise WorkerError.new("EINHORN_MASTER_PID environment variable is #{ppid_s.inspect}, but my parent's pid is #{Process.ppid.inspect}. This probably means that I am a subprocess of an Einhorn worker, but am not one myself.") unless Process.ppid == ppid true else raise WorkerError.new("No EINHORN_MASTER_PID environment variable set. Are you running your process under Einhorn?") unless Process.ppid == ppid end end |
.graceful_shutdown(&blk) ⇒ Object
Call this to handle graceful shutdown requests to your app.
131 132 133 |
# File 'lib/einhorn/worker.rb', line 131 def self.graceful_shutdown(&blk) Signal.trap('USR2', &blk) end |
.is_worker? ⇒ Boolean
8 9 10 11 12 13 14 15 16 |
# File 'lib/einhorn/worker.rb', line 8 def self.is_worker? begin ensure_worker! rescue WorkerError false else true end end |
.ping!(request_id, discovery = :env, arg = nil) ⇒ Object
Call this to indicate your child process is up and in a healthy state. Arguments:
@request_id: Identifies the request ID of the worker, can be used to debug wedged workers.
@discovery: How to discover the master process’s command socket.
:env: Discover the path from ENV['EINHORN_SOCK_PATH']
:fd: Just use the file descriptor in ENV['EINHORN_SOCK_FD'].
Must run the master with the -g flag. This is mostly
useful if you don't have a nice library like Einhorn::Worker.
Then @arg being true causes the FD to be left open after ACK;
otherwise it is closed.
:direct: Provide the path to the command socket in @arg.
87 88 89 90 91 |
# File 'lib/einhorn/worker.rb', line 87 def self.ping!(request_id, discovery=:env, arg=nil) handle_command_socket(discovery, arg) do |client| client.send_command('command' => 'worker:ping', 'pid' => $$, 'request_id' => request_id) end end |
.socket(number = nil) ⇒ Object
93 94 95 96 |
# File 'lib/einhorn/worker.rb', line 93 def self.socket(number=nil) number ||= 0 einhorn_fd(number) end |
.socket!(number = nil) ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/einhorn/worker.rb', line 98 def self.socket!(number=nil) number ||= 0 unless count = einhorn_fd_count raise "No EINHORN_FD_COUNT provided in environment. Are you running under Einhorn?" end unless number < count raise "Only #{count} FDs available, but FD #{number} was requested" end unless fd = einhorn_fd(number) raise "No EINHORN_FD_#{number} provided in environment. That's pretty weird" end fd end |