Module: Einhorn
- Extended by:
- Third::LittlePlugger
- Defined in:
- lib/einhorn.rb,
lib/einhorn/event.rb,
lib/einhorn/third.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, Plugins, State, Third, TransientState, Worker, WorkerPool
Classes: Client
Constant Summary
collapse
- VERSION =
'0.5.1'
Class Method Summary
collapse
-
.bind(addr, port, flags) ⇒ Object
-
.is_script(file) ⇒ Object
Not really a thing, but whatever.
-
.log_debug(msg) ⇒ Object
Implement these ourselves so it plays nicely with state persistence.
-
.log_error(msg, tag = nil) ⇒ Object
-
.log_info(msg, tag = nil) ⇒ Object
-
.master_ps_name ⇒ Object
-
.plugins_send(sym, *args) ⇒ Object
-
.preload ⇒ Object
-
.print_state ⇒ Object
-
.renice_self ⇒ Object
-
.restore_state(state) ⇒ Object
-
.run ⇒ Object
-
.send_tagged_message(tag, message, last = false) ⇒ Object
-
.set_argv(cmd, set_ps_name) ⇒ Object
-
.set_master_ps_name ⇒ Object
-
.socketify!(cmd) ⇒ Object
This duplicates some code from the environment path, but is deprecated so that’s ok.
-
.socketify_env! ⇒ Object
-
.update_plugin_states(states) ⇒ Object
-
.update_state(store, store_name, old_state) ⇒ Object
-
.which(cmd) ⇒ Object
-
.worker_ps_name ⇒ Object
default_plugin_module, default_plugin_path, extended, underscore, version
Class Method Details
.bind(addr, port, flags) ⇒ Object
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
# File 'lib/einhorn.rb', line 148
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.
216
217
218
219
220
221
|
# File 'lib/einhorn.rb', line 216
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
169
170
171
|
# File 'lib/einhorn.rb', line 169
def self.log_debug(msg)
$stderr.puts("#{log_tag} DEBUG: #{msg}") if Einhorn::State.verbosity <= 0
end
|
.log_error(msg, tag = nil) ⇒ Object
176
177
178
179
|
# File 'lib/einhorn.rb', line 176
def self.log_error(msg, tag=nil)
$stderr.puts("#{log_tag} ERROR: #{msg}") if Einhorn::State.verbosity <= 2
self.send_tagged_message(tag, "ERROR: #{msg}") if tag
end
|
.log_info(msg, tag = nil) ⇒ Object
172
173
174
175
|
# File 'lib/einhorn.rb', line 172
def self.log_info(msg, tag=nil)
$stderr.puts("#{log_tag} INFO: #{msg}") if Einhorn::State.verbosity <= 1
self.send_tagged_message(tag, msg) if tag
end
|
.master_ps_name ⇒ Object
277
278
279
|
# File 'lib/einhorn.rb', line 277
def self.master_ps_name
"einhorn: #{worker_ps_name}"
end
|
.plugins_send(sym, *args) ⇒ Object
15
16
17
18
19
|
# File 'lib/einhorn.rb', line 15
def self.plugins_send(sym, *args)
plugins.values.each do |plugin|
plugin.send(sym, *args) if plugin.respond_to? sym
end
end
|
.preload ⇒ Object
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
|
# File 'lib/einhorn.rb', line 223
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)", :upgrade)
load path
else
log_info("Requiring #{path} (if this hangs, make sure your code can be properly loaded as a library)", :upgrade)
require path
end
rescue Exception => e
log_info("Proceeding with postload -- could not load #{path}: #{e} (#{e.class})\n #{e.backtrace.join("\n ")}", :upgrade)
else
if defined?(einhorn_main)
log_info("Successfully loaded #{path}", :upgrade)
Einhorn::TransientState.preloaded = true
else
log_info("Proceeding with postload -- loaded #{path}, but no einhorn_main method was defined", :upgrade)
end
end
end
end
|
.print_state ⇒ Object
144
145
146
|
# File 'lib/einhorn.rb', line 144
def self.print_state
log_info(Einhorn::State.state.pretty_inspect)
end
|
.renice_self ⇒ Object
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
|
# File 'lib/einhorn.rb', line 285
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
.send_tagged_message(tag, message, last = false) ⇒ Object
.set_argv(cmd, set_ps_name) ⇒ Object
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
|
# File 'lib/einhorn.rb', line 249
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
273
274
275
|
# File 'lib/einhorn.rb', line 273
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.
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
|
# File 'lib/einhorn.rb', line 313
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
304
305
306
307
308
309
|
# File 'lib/einhorn.rb', line 304
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_plugin_states(states) ⇒ Object
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
# File 'lib/einhorn.rb', line 127
def self.update_plugin_states(states)
plugin_messages = []
(states || {}).each do |name, plugin_state|
plugin = Einhorn.plugins[name]
unless plugin && plugin.const_defined?(:State)
plugin_messages << "No state defined in this version of the #{name} " +
"plugin; dropping values for keys #{plugin_state.keys.inspect}"
next
end
updated_state, plugin_message = update_state(plugin::State, "plugin #{name}", plugin_state)
plugin_messages << plugin_message if plugin_message
plugin::State.state = updated_state
end
plugin_messages
end
|
.update_state(store, store_name, old_state) ⇒ Object
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
# File 'lib/einhorn.rb', line 106
def self.update_state(store, store_name, old_state)
updated_state = old_state.dup
default = store.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 for #{store_name} has changed: #{message.join(', ')}"
[updated_state, message]
end
|
.which(cmd) ⇒ Object
202
203
204
205
206
207
208
209
210
211
212
213
|
# File 'lib/einhorn.rb', line 202
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
|