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
27 28 29 30 |
# File 'lib/einhorn/worker.rb', line 27 def self.ack(*args) ack!(*args) rescue WorkerError 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 :fd: Just use the file descriptor in ENV. 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.
64 65 66 67 68 |
# File 'lib/einhorn/worker.rb', line 64 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.
40 41 42 43 44 45 46 47 |
# File 'lib/einhorn/worker.rb', line 40 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
112 113 114 115 116 117 |
# File 'lib/einhorn/worker.rb', line 112 def self.einhorn_fd(n) unless (raw_fd = ENV["EINHORN_FD_#{n}"]) return nil end Integer(raw_fd) end |
.einhorn_fd_count ⇒ Object
119 120 121 122 123 124 |
# File 'lib/einhorn/worker.rb', line 119 def self.einhorn_fd_count unless (raw_count = ENV["EINHORN_FD_COUNT"]) return 0 end Integer(raw_count) end |
.ensure_worker! ⇒ Object
16 17 18 19 20 21 22 23 24 25 |
# File 'lib/einhorn/worker.rb', line 16 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.
127 128 129 |
# File 'lib/einhorn/worker.rb', line 127 def self.graceful_shutdown(&blk) Signal.trap("USR2", &blk) end |
.is_worker? ⇒ Boolean
8 9 10 11 12 13 14 |
# File 'lib/einhorn/worker.rb', line 8 def self.is_worker? ensure_worker! rescue WorkerError false else true 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 :fd: Just use the file descriptor in ENV. 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.
83 84 85 86 87 |
# File 'lib/einhorn/worker.rb', line 83 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
89 90 91 92 |
# File 'lib/einhorn/worker.rb', line 89 def self.socket(number = nil) number ||= 0 einhorn_fd(number) end |
.socket!(number = nil) ⇒ Object
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/einhorn/worker.rb', line 94 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 |