Module: Einhorn
- Defined in:
- lib/einhorn.rb,
lib/einhorn/event.rb,
lib/einhorn/client.rb,
lib/einhorn/worker.rb,
lib/einhorn/command.rb,
lib/einhorn/version.rb,
lib/einhorn/worker_pool.rb
Defined Under Namespace
Modules: AbstractState, Command, Event, State, TransientState, Worker, WorkerPool
Classes: Client
Constant Summary
collapse
- VERSION =
'0.4.4'
Class Method Summary
collapse
Class Method Details
.bind(addr, port, flags) ⇒ Object
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
# File 'lib/einhorn.rb', line 118
def self.bind(addr, port, flags)
log_info("Binding to #{addr}:#{port} with flags #{flags.inspect}")
sd = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
if flags.include?('r') || flags.include?('so_reuseaddr')
sd.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
end
sd.bind(Socket.pack_sockaddr_in(port, addr))
sd.listen(Einhorn::State.config[:backlog])
if flags.include?('n') || flags.include?('o_nonblock')
fl = sd.fcntl(Fcntl::F_GETFL)
sd.fcntl(Fcntl::F_SETFL, fl | Fcntl::O_NONBLOCK)
end
Einhorn::TransientState.socket_handles << sd
sd.fileno
end
|
.is_script(file) ⇒ Object
Not really a thing, but whatever.
180
181
182
183
184
185
|
# File 'lib/einhorn.rb', line 180
def self.is_script(file)
File.open(file) do |f|
bytes = f.read(2)
bytes == '#!'
end
end
|
.log_debug(msg) ⇒ Object
Implement these ourselves so it plays nicely with state persistence
139
140
141
|
# File 'lib/einhorn.rb', line 139
def self.log_debug(msg)
$stderr.puts("#{log_tag} DEBUG: #{msg}") if Einhorn::State.verbosity <= 0
end
|
.log_error(msg) ⇒ Object
145
146
147
|
# File 'lib/einhorn.rb', line 145
def self.log_error(msg)
$stderr.puts("#{log_tag} ERROR: #{msg}") if Einhorn::State.verbosity <= 2
end
|
.log_info(msg) ⇒ Object
142
143
144
|
# File 'lib/einhorn.rb', line 142
def self.log_info(msg)
$stderr.puts("#{log_tag} INFO: #{msg}") if Einhorn::State.verbosity <= 1
end
|
.master_ps_name ⇒ Object
241
242
243
|
# File 'lib/einhorn.rb', line 241
def self.master_ps_name
"einhorn: #{worker_ps_name}"
end
|
.preload ⇒ Object
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
|
# File 'lib/einhorn.rb', line 187
def self.preload
if path = Einhorn::State.path
set_argv(Einhorn::State.cmd, false)
begin
if !path.end_with?('.rb') && File.exists?(path)
log_info("Loading #{path} (if this hangs, make sure your code can be properly loaded as a library)")
load path
else
log_info("Requiring #{path} (if this hangs, make sure your code can be properly loaded as a library)")
require path
end
rescue Exception => e
log_info("Proceeding with postload -- could not load #{path}: #{e} (#{e.class})\n #{e.backtrace.join("\n ")}")
else
if defined?(einhorn_main)
log_info("Successfully loaded #{path}")
Einhorn::TransientState.preloaded = true
else
log_info("Proceeding with postload -- loaded #{path}, but no einhorn_main method was defined")
end
end
end
end
|
.print_state ⇒ Object
114
115
116
|
# File 'lib/einhorn.rb', line 114
def self.print_state
log_info(Einhorn::State.state.pretty_inspect)
end
|
.renice_self ⇒ Object
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
# File 'lib/einhorn.rb', line 249
def self.renice_self
whatami = Einhorn::TransientState.whatami
return unless nice = Einhorn::State.nice[whatami]
pid = $$
unless nice.kind_of?(Fixnum)
raise "Nice must be a fixnum: #{nice.inspect}"
end
cmd = "#{Einhorn::State.nice[:renice_cmd]} #{nice} -p #{pid}"
log_info("Running #{cmd.inspect} to renice self to level #{nice}")
`#{cmd}`
unless $?.exitstatus == 0
log_error("Renice command exited with status: #{$?.inspect}, but continuing on anyway.")
end
end
|
.restore_state(state) ⇒ Object
.set_argv(cmd, set_ps_name) ⇒ Object
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
|
# File 'lib/einhorn.rb', line 213
def self.set_argv(cmd, set_ps_name)
idx = 0
if cmd[0] =~ /(^|\/)ruby$/
idx = 1
elsif !is_script(cmd[0])
log_info("WARNING: Going to set $0 to #{cmd[idx]}, but it doesn't look like a script")
end
if set_ps_name
$0 = worker_ps_name
end
ARGV[0..-1] = cmd[idx+1..-1]
log_info("Set#{set_ps_name ? " $0 = #{$0.inspect}, " : nil} ARGV = #{ARGV.inspect}")
end
|
.set_master_ps_name ⇒ Object
237
238
239
|
# File 'lib/einhorn.rb', line 237
def self.set_master_ps_name
$0 = master_ps_name
end
|
.socketify!(cmd) ⇒ Object
This duplicates some code from the environment path, but is deprecated so that’s ok.
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
|
# File 'lib/einhorn.rb', line 277
def self.socketify!(cmd)
cmd.map! do |arg|
if arg =~ /^(.*=|)srv:([^:]+):(\d+)((?:,\w+)*)$/
log_error("Using deprecated command-line configuration for Einhorn; should upgrade to the environment variable interface.")
opt = $1
host = $2
port = $3
flags = $4.split(',').select {|flag| flag.length > 0}.map {|flag| flag.downcase}
fd = (Einhorn::State.sockets[[host, port]] ||= bind(host, port, flags))
"#{opt}#{fd}"
else
arg
end
end
end
|
.socketify_env! ⇒ Object
268
269
270
271
272
273
|
# File 'lib/einhorn.rb', line 268
def self.socketify_env!
Einhorn::State.bind.each do |host, port, flags|
fd = bind(host, port, flags)
Einhorn::State.bind_fds << fd
end
end
|
.update_state(old_state) ⇒ Object
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
# File 'lib/einhorn.rb', line 93
def self.update_state(old_state)
updated_state = old_state.dup
default = Einhorn::State.default_state
added_keys = default.keys - old_state.keys
deleted_keys = old_state.keys - default.keys
return [updated_state, nil] if added_keys.length == 0 && deleted_keys.length == 0
added_keys.each {|key| updated_state[key] = default[key]}
deleted_keys.each {|key| updated_state.delete(key)}
message = []
message << "adding default values for #{added_keys.inspect}"
message << "deleting values for #{deleted_keys.inspect}"
message = "State format has changed: #{message.join(', ')}"
[updated_state, message]
end
|
.which(cmd) ⇒ Object
166
167
168
169
170
171
172
173
174
175
176
177
|
# File 'lib/einhorn.rb', line 166
def self.which(cmd)
if cmd.include?('/')
return cmd if File.exists?(cmd)
raise "Could not find #{cmd}"
else
ENV['PATH'].split(':').each do |f|
abs = File.join(f, cmd)
return abs if File.exists?(abs)
end
raise "Could not find #{cmd} in PATH"
end
end
|