lib/einhorn/command/interface.rb in einhorn-0.4.9 vs lib/einhorn/command/interface.rb in einhorn-0.5.0

- old
+ new

@@ -200,51 +200,63 @@ def self.command(name, description=nil, &code) @@commands[name] = {:description => description, :code => code} end def self.process_command(conn, command) - response = generate_response(conn, command) - if !response.nil? - send_message(conn, response) + begin + request = Einhorn::Client::Transport.deserialize_message(command) + rescue Einhorn::Client::Transport::ParseError + end + unless request.kind_of?(Hash) + send_message(conn, "Could not parse command") + return + end + + message = generate_message(conn, request) + if !message.nil? + send_message(conn, message, request['id'], true) else conn.log_debug("Got back nil response, so not responding to command.") end end - def self.send_message(conn, response) - if response.kind_of?(String) - response = {'message' => response} + def self.send_tagged_message(tag, message, last=false) + Einhorn::Event.connections.each do |conn| + if id = conn.subscription(tag) + self.send_message(conn, message, id, last) + conn.unsubscribe(tag) if last + end end - Einhorn::Client::Transport.send_message(conn, response) end - def self.generate_response(conn, command) - begin - request = Einhorn::Client::Transport.deserialize_message(command) - rescue ArgumentError => e - return { - 'message' => "Could not parse command: #{e}" - } + def self.send_message(conn, message, request_id=nil, last=false) + if request_id + response = {'message' => message, 'request_id' => request_id } + response['wait'] = true unless last + else + # support old-style protocol + response = {'message' => message} end + Einhorn::Client::Transport.send_message(conn, response) + end + def self.generate_message(conn, request) unless command_name = request['command'] - return { - 'message' => 'No "command" parameter provided; not sure what you want me to do.' - } + return 'No "command" parameter provided; not sure what you want me to do.' end if command_spec = @@commands[command_name] - conn.log_debug("Received command: #{command.inspect}") + conn.log_debug("Received command: #{request.inspect}") begin return command_spec[:code].call(conn, request) rescue StandardError => e msg = "Error while processing command #{command_name.inspect}: #{e} (#{e.class})\n #{e.backtrace.join("\n ")}" conn.log_error(msg) return msg end else - conn.log_debug("Received unrecognized command: #{command.inspect}") + conn.log_debug("Received unrecognized command: #{request.inspect}") return unrecognized_command(conn, request) end end def self.command_descriptions @@ -293,19 +305,19 @@ command 'state', "Get a dump of Einhorn's current state" do YAML.dump(Einhorn::Command.dumpable_state) end - command 'reload', 'Reload Einhorn' do |conn, _| + command 'reload', 'Reload Einhorn' do |conn, request| # TODO: make reload actually work (command socket reopening is # an issue). Would also be nice if user got a confirmation that # the reload completed, though that's not strictly necessary. # In the normal case, this will do a write # synchronously. Otherwise, the bytes will be stuck into the # buffer and lost upon reload. - send_message(conn, 'Reloading, as commanded') + send_message(conn, 'Reloading, as commanded', request['id'], true) Einhorn::Command.reload end command 'inc', 'Increment the number of Einhorn child processes' do Einhorn::Command.increment @@ -321,13 +333,16 @@ command 'louder', 'Increase verbosity' do Einhorn::Command.louder end - command 'upgrade', 'Upgrade all Einhorn workers. This may result in Einhorn reloading its own code as well.' do |conn, _| - # TODO: send confirmation when this is done - send_message(conn, 'Upgrading, as commanded') - # This or may not return + command 'upgrade', 'Upgrade all Einhorn workers. This may result in Einhorn reloading its own code as well.' do |conn, request| + # send first message directly for old clients that don't support request + # ids or subscriptions. Everything else is sent tagged with request id + # for new clients. + send_message(conn, 'Upgrading, as commanded', request['id']) + conn.subscribe(:upgrade, request['id']) + # If the app is preloaded this doesn't return. Einhorn::Command.full_upgrade nil end command 'signal', 'Send one or more signals to all workers (args: SIG1 [SIG2 ...])' do |conn, request|