lib/qwirk/publish_handle.rb
def read_response(timeout, &block)
      raise "Invalid call to read_response for #{@producer}, not setup for responding" unless @producer.response_options
      # Creates a block for reading the responses for a given message_id (adapter_info).  The block will be passed an object
      # that responds to timeout_read(timeout) with a [original_message_id, response_message, worker_name] tri or nil if no message is read.
      # This is used in the RPC mechanism where a publish might wait for 1 or more workers to respond.
      @producer.impl.with_response(@adapter_info) do |consumer|
        if block_given?
          return read_multiple_response(consumer, timeout, &block)
        else
          tri = read_single_response(consumer, timeout)
          if tri
            response = tri[1]
            raise response if response.kind_of?(Qwirk::RemoteException)
            return response
          else
            @timeout = !tri
            return nil
          end
        end
      end
    end
def read_response(timeout, &block)
      raise "Invalid call to read_response for #{@producer}, not setup for responding" unless @producer.response_options
      # Creates a block for reading the responses for a given message_id (adapter_info).  The block will be passed an object
      # that responds to timeout_read(timeout) with a [original_message_id, response_message, worker_name] tri or nil if no message is read.
      # This is used in the RPC mechanism where a publish might wait for 1 or more workers to respond.
      @producer.impl.with_response(@adapter_info) do |consumer|
        if block_given?
          return read_multiple_response(consumer, timeout, &block)
        else
          tri = read_single_response(consumer, timeout)
          if tri
            response = tri[1]
            raise response if response.kind_of?(Qwirk::RemoteException)
            return response
          else
            @timeout = !tri
            return nil
          end
        end
      end
    end
Waits the given timeout for a response message on the queue.

 If called w/o a block:
   Returns the message
   Returns nil on timeout
   Raises RemoteException on a remote exception

 If called with a block, for instance:
   handle.read_response(timeout) do |response|
     response.on_message 'CharCount' do |hash|
       puts "CharCount returned #{hash.inspect}"
     end
     response.on_message 'Length', 'Reverse' do |val|
       puts "#{response.name} returned #{val}"
     end
     response.on_message 'ExceptionRaiser' do |val|
       puts "#{response.name} didn't raise an exception but returned #{val}"
     end
     response.on_timeout 'Reverse' do
       puts "Reverse has it's own timeout handler"
     end
     response.on_timeout do
       puts "#{response.name} did not respond in time"
     end
     response.on_remote_exception 'ExceptionRaiser' do
       puts "It figures that ExceptionRaiser would raise an exception"
     end
     response.on_remote_exception do |e|
       puts "#{response.name} raised an exception #{e.message}\n\t#{e.backtrace.join("\n\t")}"
     end
   end

 The specified blocks will be called for each response.  For instance, LengthWorker#request
 might return 4 and "Length returned 4" would be displayed.  If it failed to respond within the
 timeout, then "Length did no respond in time" would be displayed.
 For Workers that raise an exception, they will either be handled by their specific handler if it exists or
 the default exception handler.  If that doesn't exist either, then the RemoteException will be raised for the
 whole read_response call.  Timeouts will also be handled by the default timeout handler unless a specific one
 is specified.  All messages must have a specific handler specified because the call won't return until all
 specified handlers either return, timeout, or return an exception.