bunny 1.4.1 → 1.5.0.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -1
- data/ChangeLog.md +19 -5
- data/README.md +23 -3
- data/examples/guides/extensions/basic_nack.rb +1 -1
- data/examples/guides/extensions/dead_letter_exchange.rb +1 -1
- data/examples/guides/queues/redeliveries.rb +2 -2
- data/lib/bunny.rb +1 -1
- data/lib/bunny/channel.rb +34 -21
- data/lib/bunny/exceptions.rb +17 -2
- data/lib/bunny/exchange.rb +14 -22
- data/lib/bunny/queue.rb +19 -12
- data/lib/bunny/session.rb +67 -57
- data/lib/bunny/version.rb +1 -1
- data/spec/config/enabled_plugins +1 -0
- data/spec/config/rabbitmq.config +18 -0
- data/spec/higher_level_api/integration/basic_ack_spec.rb +29 -2
- data/spec/higher_level_api/integration/basic_consume_with_objects_spec.rb +1 -1
- data/spec/higher_level_api/integration/basic_nack_spec.rb +5 -5
- data/spec/higher_level_api/integration/basic_reject_spec.rb +3 -3
- data/spec/higher_level_api/integration/connection_recovery_spec.rb +79 -2
- data/spec/higher_level_api/integration/connection_spec.rb +24 -0
- data/spec/higher_level_api/integration/dead_lettering_spec.rb +1 -1
- data/spec/higher_level_api/integration/exchange_unbind_spec.rb +1 -1
- data/spec/higher_level_api/integration/message_properties_access_spec.rb +1 -1
- data/spec/issues/issue78_spec.rb +2 -2
- data/spec/spec_helper.rb +6 -7
- data/spec/tls/ca_certificate.pem +18 -0
- data/spec/tls/ca_key.pem +27 -0
- data/spec/tls/client_cert.pem +16 -16
- data/spec/tls/client_key.pem +25 -25
- data/spec/tls/server_cert.pem +16 -16
- data/spec/tls/server_key.pem +25 -25
- metadata +12 -10
- data/.ruby-version +0 -1
- data/lib/bunny/compatibility.rb +0 -24
- data/spec/compatibility/queue_declare_spec.rb +0 -44
- data/spec/compatibility/queue_declare_with_default_channel_spec.rb +0 -33
    
        data/lib/bunny/session.rb
    CHANGED
    
    | @@ -82,9 +82,8 @@ module Bunny | |
| 82 82 |  | 
| 83 83 | 
             
                # @return [Bunny::Transport]
         | 
| 84 84 | 
             
                attr_reader :transport
         | 
| 85 | 
            -
                attr_reader :status, : | 
| 85 | 
            +
                attr_reader :status, :port, :heartbeat, :user, :pass, :vhost, :frame_max, :channel_max, :threaded
         | 
| 86 86 | 
             
                attr_reader :server_capabilities, :server_properties, :server_authentication_mechanisms, :server_locales
         | 
| 87 | 
            -
                attr_reader :default_channel
         | 
| 88 87 | 
             
                attr_reader :channel_id_allocator
         | 
| 89 88 | 
             
                # Authentication mechanism, e.g. "PLAIN" or "EXTERNAL"
         | 
| 90 89 | 
             
                # @return [String]
         | 
| @@ -99,6 +98,7 @@ module Bunny | |
| 99 98 | 
             
                # @param [Hash] optz Extra options not related to connection
         | 
| 100 99 | 
             
                #
         | 
| 101 100 | 
             
                # @option connection_string_or_opts [String] :host ("127.0.0.1") Hostname or IP address to connect to
         | 
| 101 | 
            +
                # @option connection_string_or_opts [Array<String>] :hosts (["127.0.0.1"]) list of hostname or IP addresses to select hostname from when connecting
         | 
| 102 102 | 
             
                # @option connection_string_or_opts [Integer] :port (5672) Port RabbitMQ listens on
         | 
| 103 103 | 
             
                # @option connection_string_or_opts [String] :username ("guest") Username
         | 
| 104 104 | 
             
                # @option connection_string_or_opts [String] :password ("guest") Password
         | 
| @@ -109,8 +109,10 @@ module Bunny | |
| 109 109 | 
             
                # @option connection_string_or_opts [String] :tls_cert (nil) Path to client TLS/SSL certificate file (.pem)
         | 
| 110 110 | 
             
                # @option connection_string_or_opts [String] :tls_key (nil) Path to client TLS/SSL private key file (.pem)
         | 
| 111 111 | 
             
                # @option connection_string_or_opts [Array<String>] :tls_ca_certificates Array of paths to TLS/SSL CA files (.pem), by default detected from OpenSSL configuration
         | 
| 112 | 
            +
                # @option connection_string_or_opts [String] :verify_peer (true) Whether TLS peer verification should be performed
         | 
| 112 113 | 
             
                # @option connection_string_or_opts [Integer] :continuation_timeout (4000) Timeout for client operations that expect a response (e.g. {Bunny::Queue#get}), in milliseconds.
         | 
| 113 114 | 
             
                # @option connection_string_or_opts [Integer] :connection_timeout (5) Timeout in seconds for connecting to the server.
         | 
| 115 | 
            +
                # @option connection_string_or_opts [Proc] :hosts_shuffle_strategy A Proc that reorders a list of host strings, defaults to Array#shuffle
         | 
| 114 116 | 
             
                #
         | 
| 115 117 | 
             
                # @option optz [String] :auth_mechanism ("PLAIN") Authentication mechanism, PLAIN or EXTERNAL
         | 
| 116 118 | 
             
                # @option optz [String] :locale ("PLAIN") Locale RabbitMQ should use
         | 
| @@ -128,8 +130,12 @@ module Bunny | |
| 128 130 | 
             
                           connection_string_or_opts
         | 
| 129 131 | 
             
                         end.merge(optz)
         | 
| 130 132 |  | 
| 133 | 
            +
                  @default_hosts_shuffle_strategy = Proc.new { |hosts| hosts.shuffle }
         | 
| 134 | 
            +
             | 
| 131 135 | 
             
                  @opts            = opts
         | 
| 132 | 
            -
                  @ | 
| 136 | 
            +
                  @hosts           = self.hostnames_from(opts)
         | 
| 137 | 
            +
                  @host_index      = 0
         | 
| 138 | 
            +
             | 
| 133 139 | 
             
                  @port            = self.port_from(opts)
         | 
| 134 140 | 
             
                  @user            = self.username_from(opts)
         | 
| 135 141 | 
             
                  @pass            = self.password_from(opts)
         | 
| @@ -173,6 +179,8 @@ module Bunny | |
| 173 179 | 
             
                  # the non-reentrant Ruby mutexes. MK.
         | 
| 174 180 | 
             
                  @transport_mutex     = @mutex_impl.new
         | 
| 175 181 | 
             
                  @status_mutex        = @mutex_impl.new
         | 
| 182 | 
            +
                  @host_index_mutex    = @mutex_impl.new
         | 
| 183 | 
            +
             | 
| 176 184 | 
             
                  @channels            = Hash.new
         | 
| 177 185 |  | 
| 178 186 | 
             
                  @origin_thread       = Thread.current
         | 
| @@ -210,6 +218,14 @@ module Bunny | |
| 210 218 | 
             
                  @threaded
         | 
| 211 219 | 
             
                end
         | 
| 212 220 |  | 
| 221 | 
            +
                def host
         | 
| 222 | 
            +
                  @transport ? @transport.host : @hosts[@host_index]
         | 
| 223 | 
            +
                end
         | 
| 224 | 
            +
             | 
| 225 | 
            +
                def reset_host_index
         | 
| 226 | 
            +
                  @host_index_mutex.synchronize { @host_index = 0 }
         | 
| 227 | 
            +
                end
         | 
| 228 | 
            +
             | 
| 213 229 | 
             
                # @private
         | 
| 214 230 | 
             
                attr_reader :mutex_impl
         | 
| 215 231 |  | 
| @@ -232,6 +248,7 @@ module Bunny | |
| 232 248 | 
             
                # @see http://rubybunny.info/articles/connecting.html
         | 
| 233 249 | 
             
                # @api public
         | 
| 234 250 | 
             
                def start
         | 
| 251 | 
            +
             | 
| 235 252 | 
             
                  return self if connected?
         | 
| 236 253 |  | 
| 237 254 | 
             
                  @status_mutex.synchronize { @status = :connecting }
         | 
| @@ -241,27 +258,42 @@ module Bunny | |
| 241 258 | 
             
                  self.reset_continuations
         | 
| 242 259 |  | 
| 243 260 | 
             
                  begin
         | 
| 244 | 
            -
                    # close existing transport if we have one,
         | 
| 245 | 
            -
                    # to not leak sockets
         | 
| 246 | 
            -
                    @transport.maybe_initialize_socket
         | 
| 247 261 |  | 
| 248 | 
            -
                     | 
| 249 | 
            -
                    @transport.connect
         | 
| 262 | 
            +
                    begin
         | 
| 250 263 |  | 
| 251 | 
            -
             | 
| 252 | 
            -
                       | 
| 253 | 
            -
             | 
| 264 | 
            +
                      # close existing transport if we have one,
         | 
| 265 | 
            +
                      # to not leak sockets
         | 
| 266 | 
            +
                      @transport.maybe_initialize_socket
         | 
| 254 267 |  | 
| 255 | 
            -
             | 
| 256 | 
            -
             | 
| 268 | 
            +
                      @transport.post_initialize_socket
         | 
| 269 | 
            +
                      @transport.connect
         | 
| 257 270 |  | 
| 258 | 
            -
             | 
| 259 | 
            -
             | 
| 271 | 
            +
                      if @socket_configurator
         | 
| 272 | 
            +
                        @transport.configure_socket(&@socket_configurator)
         | 
| 273 | 
            +
                      end
         | 
| 260 274 |  | 
| 261 | 
            -
             | 
| 262 | 
            -
             | 
| 275 | 
            +
                      self.init_connection
         | 
| 276 | 
            +
                      self.open_connection
         | 
| 277 | 
            +
             | 
| 278 | 
            +
                      @reader_loop = nil
         | 
| 279 | 
            +
                      self.start_reader_loop if threaded?
         | 
| 280 | 
            +
             | 
| 281 | 
            +
                    rescue TCPConnectionFailed => e
         | 
| 282 | 
            +
                      self.initialize_transport
         | 
| 283 | 
            +
             | 
| 284 | 
            +
                      @logger.warn e.message
         | 
| 285 | 
            +
                      @logger.warn "Retrying connection on next host in line: #{@transport.host}:#{@transport.port}"
         | 
| 286 | 
            +
             | 
| 287 | 
            +
                      return self.start
         | 
| 288 | 
            +
                    rescue Exception
         | 
| 289 | 
            +
                      @status_mutex.synchronize { @status = :not_connected }
         | 
| 290 | 
            +
                      raise
         | 
| 291 | 
            +
                    end
         | 
| 292 | 
            +
             | 
| 293 | 
            +
                  rescue HostListDepleted
         | 
| 294 | 
            +
                    self.reset_host_index
         | 
| 263 295 | 
             
                    @status_mutex.synchronize { @status = :not_connected }
         | 
| 264 | 
            -
                    raise  | 
| 296 | 
            +
                    raise TCPConnectionFailedForAllHosts
         | 
| 265 297 | 
             
                  end
         | 
| 266 298 |  | 
| 267 299 | 
             
                  self
         | 
| @@ -355,40 +387,6 @@ module Bunny | |
| 355 387 | 
             
                  @automatically_recover
         | 
| 356 388 | 
             
                end
         | 
| 357 389 |  | 
| 358 | 
            -
                #
         | 
| 359 | 
            -
                # Backwards compatibility
         | 
| 360 | 
            -
                #
         | 
| 361 | 
            -
             | 
| 362 | 
            -
                # @private
         | 
| 363 | 
            -
                def queue(*args)
         | 
| 364 | 
            -
                  @default_channel.queue(*args)
         | 
| 365 | 
            -
                end
         | 
| 366 | 
            -
             | 
| 367 | 
            -
                # @private
         | 
| 368 | 
            -
                def direct(*args)
         | 
| 369 | 
            -
                  @default_channel.direct(*args)
         | 
| 370 | 
            -
                end
         | 
| 371 | 
            -
             | 
| 372 | 
            -
                # @private
         | 
| 373 | 
            -
                def fanout(*args)
         | 
| 374 | 
            -
                  @default_channel.fanout(*args)
         | 
| 375 | 
            -
                end
         | 
| 376 | 
            -
             | 
| 377 | 
            -
                # @private
         | 
| 378 | 
            -
                def topic(*args)
         | 
| 379 | 
            -
                  @default_channel.topic(*args)
         | 
| 380 | 
            -
                end
         | 
| 381 | 
            -
             | 
| 382 | 
            -
                # @private
         | 
| 383 | 
            -
                def headers(*args)
         | 
| 384 | 
            -
                  @default_channel.headers(*args)
         | 
| 385 | 
            -
                end
         | 
| 386 | 
            -
             | 
| 387 | 
            -
                # @private
         | 
| 388 | 
            -
                def exchange(*args)
         | 
| 389 | 
            -
                  @default_channel.exchange(*args)
         | 
| 390 | 
            -
                end
         | 
| 391 | 
            -
             | 
| 392 390 | 
             
                # Defines a callback that will be executed when RabbitMQ blocks the connection
         | 
| 393 391 | 
             
                # because it is running low on memory or disk space (as configured via config file
         | 
| 394 392 | 
             
                # and/or rabbitmqctl).
         | 
| @@ -646,6 +644,8 @@ module Bunny | |
| 646 644 | 
             
                  begin
         | 
| 647 645 | 
             
                    sleep @network_recovery_interval
         | 
| 648 646 | 
             
                    @logger.debug "About to start connection recovery..."
         | 
| 647 | 
            +
             | 
| 648 | 
            +
                    self.reset_host_index # since we are starting a fresh try.
         | 
| 649 649 | 
             
                    self.initialize_transport
         | 
| 650 650 | 
             
                    self.start
         | 
| 651 651 |  | 
| @@ -654,7 +654,7 @@ module Bunny | |
| 654 654 |  | 
| 655 655 | 
             
                      recover_channels
         | 
| 656 656 | 
             
                    end
         | 
| 657 | 
            -
                  rescue TCPConnectionFailed, AMQ::Protocol::EmptyResponseError => e
         | 
| 657 | 
            +
                  rescue TCPConnectionFailedForAllHosts, TCPConnectionFailed, AMQ::Protocol::EmptyResponseError => e
         | 
| 658 658 | 
             
                    @logger.warn "TCP connection failed, reconnecting in #{@network_recovery_interval} seconds"
         | 
| 659 659 | 
             
                    sleep @network_recovery_interval
         | 
| 660 660 | 
             
                    retry if recoverable_network_failure?(e)
         | 
| @@ -663,6 +663,9 @@ module Bunny | |
| 663 663 |  | 
| 664 664 | 
             
                # @private
         | 
| 665 665 | 
             
                def recover_channels
         | 
| 666 | 
            +
                  # default channel is reopened right after connection
         | 
| 667 | 
            +
                  # negotiation is completed, so make sure we do not try to open
         | 
| 668 | 
            +
                  # it twice. MK.
         | 
| 666 669 | 
             
                  @channels.each do |n, ch|
         | 
| 667 670 | 
             
                    ch.open
         | 
| 668 671 |  | 
| @@ -726,8 +729,10 @@ module Bunny | |
| 726 729 | 
             
                end
         | 
| 727 730 |  | 
| 728 731 | 
             
                # @private
         | 
| 729 | 
            -
                def  | 
| 730 | 
            -
                  options | 
| 732 | 
            +
                def hostnames_from(options)
         | 
| 733 | 
            +
                  options.fetch(:hosts_shuffle_strategy, @default_hosts_shuffle_strategy).call(
         | 
| 734 | 
            +
                    [ options[:hosts] || options[:host] || options[:hostname] || DEFAULT_HOST ].flatten
         | 
| 735 | 
            +
                  )
         | 
| 731 736 | 
             
                end
         | 
| 732 737 |  | 
| 733 738 | 
             
                # @private
         | 
| @@ -923,7 +928,7 @@ module Bunny | |
| 923 928 | 
             
                # @return [String]
         | 
| 924 929 | 
             
                # @api public
         | 
| 925 930 | 
             
                def to_s
         | 
| 926 | 
            -
                  "#<#{self.class.name}:#{object_id} #{@user}@#{ | 
| 931 | 
            +
                  "#<#{self.class.name}:#{object_id} #{@user}@#{host}:#{@port}, vhost=#{@vhost}, hosts=[#{@hosts.join(',')}]>"
         | 
| 927 932 | 
             
                end
         | 
| 928 933 |  | 
| 929 934 | 
             
                protected
         | 
| @@ -1076,7 +1081,12 @@ module Bunny | |
| 1076 1081 |  | 
| 1077 1082 | 
             
                # @private
         | 
| 1078 1083 | 
             
                def initialize_transport
         | 
| 1079 | 
            -
                   | 
| 1084 | 
            +
                  if host = @hosts[ @host_index ]
         | 
| 1085 | 
            +
                    @host_index_mutex.synchronize { @host_index += 1 }
         | 
| 1086 | 
            +
                    @transport = Transport.new(self, host, @port, @opts.merge(:session_thread => @origin_thread))
         | 
| 1087 | 
            +
                  else
         | 
| 1088 | 
            +
                    raise HostListDepleted
         | 
| 1089 | 
            +
                  end
         | 
| 1080 1090 | 
             
                end
         | 
| 1081 1091 |  | 
| 1082 1092 | 
             
                # @private
         | 
    
        data/lib/bunny/version.rb
    CHANGED
    
    
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            [rabbitmq_management, rabbitmq_consistent_hash_exchange].
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            [
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              {rabbit, [
         | 
| 4 | 
            +
                {ssl_listeners, [5671]},
         | 
| 5 | 
            +
                {ssl_options, [{cacertfile,"spec/tls/cacert.pem"},
         | 
| 6 | 
            +
                               {certfile,"spec/tls/server_cert.pem"},
         | 
| 7 | 
            +
                               {keyfile,"spec/tls/server_key.pem"},
         | 
| 8 | 
            +
                               {verify,verify_none},
         | 
| 9 | 
            +
                               {fail_if_no_peer_cert,false}]} ]
         | 
| 10 | 
            +
              },
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              {rabbitmq_management,
         | 
| 13 | 
            +
                [{listener,
         | 
| 14 | 
            +
                  [{port, 15672}]
         | 
| 15 | 
            +
                }]
         | 
| 16 | 
            +
              }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            ].
         | 
| @@ -20,7 +20,7 @@ describe Bunny::Channel, "#ack" do | |
| 20 20 | 
             
                  x.publish("bunneth", :routing_key => q.name)
         | 
| 21 21 | 
             
                  sleep 0.5
         | 
| 22 22 | 
             
                  q.message_count.should == 1
         | 
| 23 | 
            -
                  delivery_details, properties, content = q.pop(: | 
| 23 | 
            +
                  delivery_details, properties, content = q.pop(:manual_ack => true)
         | 
| 24 24 |  | 
| 25 25 | 
             
                  ch.ack(delivery_details.delivery_tag, true)
         | 
| 26 26 | 
             
                  q.message_count.should == 0
         | 
| @@ -57,7 +57,7 @@ describe Bunny::Channel, "#ack" do | |
| 57 57 | 
             
                  x.publish("bunneth", :routing_key => q.name)
         | 
| 58 58 | 
             
                  sleep 0.5
         | 
| 59 59 | 
             
                  q.message_count.should == 1
         | 
| 60 | 
            -
                  _, _, content = q.pop(: | 
| 60 | 
            +
                  _, _, content = q.pop(:manual_ack => true)
         | 
| 61 61 |  | 
| 62 62 | 
             
                  ch.on_error do |ch, channel_close|
         | 
| 63 63 | 
             
                    @channel_close = channel_close
         | 
| @@ -68,4 +68,31 @@ describe Bunny::Channel, "#ack" do | |
| 68 68 | 
             
                  @channel_close.reply_code.should == AMQ::Protocol::PreconditionFailed::VALUE
         | 
| 69 69 | 
             
                end
         | 
| 70 70 | 
             
              end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
              context "with a valid (known) delivery tag" do
         | 
| 73 | 
            +
                it "gets a depricated message warning for using :ack" do
         | 
| 74 | 
            +
                  ch = connection.create_channel
         | 
| 75 | 
            +
                  q  = ch.queue("bunny.basic.ack.manual-acks", :exclusive => true)
         | 
| 76 | 
            +
                  x  = ch.default_exchange
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  x.publish("bunneth", :routing_key => q.name)
         | 
| 79 | 
            +
                  sleep 0.5
         | 
| 80 | 
            +
                  q.message_count.should == 1
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  orig_stderr = $stderr
         | 
| 83 | 
            +
                  $stderr = StringIO.new
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                  delivery_details, properties, content = q.pop(:ack => true)
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  $stderr.rewind
         | 
| 88 | 
            +
                  $stderr.string.chomp.should eq("[DEPRECATION] `:ack` is deprecated.  Please use `:manual_ack` instead.\n[DEPRECATION] `:ack` is deprecated.  Please use `:manual_ack` instead.")
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  $stderr = orig_stderr
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                  ch.ack(delivery_details.delivery_tag, true)
         | 
| 93 | 
            +
                  q.message_count.should == 0
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                  ch.close
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
              end
         | 
| 71 98 | 
             
            end
         | 
| @@ -23,7 +23,7 @@ describe Bunny::Channel, "#nack" do | |
| 23 23 | 
             
                  x.publish("bunneth", :routing_key => q.name)
         | 
| 24 24 | 
             
                  sleep(0.5)
         | 
| 25 25 | 
             
                  q.message_count.should == 1
         | 
| 26 | 
            -
                  delivery_info, _, content = q.pop(: | 
| 26 | 
            +
                  delivery_info, _, content = q.pop(:manual_ack => true)
         | 
| 27 27 |  | 
| 28 28 | 
             
                  subject.nack(delivery_info.delivery_tag, false, false)
         | 
| 29 29 | 
             
                  sleep(0.5)
         | 
| @@ -43,9 +43,9 @@ q = subject.queue("bunny.basic.nack.with-requeue-true-multi-true", :exclusive => | |
| 43 43 | 
             
                  end
         | 
| 44 44 | 
             
                  sleep(0.5)
         | 
| 45 45 | 
             
                  q.message_count.should == 3
         | 
| 46 | 
            -
                  _, _, _ = q.pop(: | 
| 47 | 
            -
                  _, _, _ = q.pop(: | 
| 48 | 
            -
                  delivery_info, _, content = q.pop(: | 
| 46 | 
            +
                  _, _, _ = q.pop(:manual_ack => true)
         | 
| 47 | 
            +
                  _, _, _ = q.pop(:manual_ack => true)
         | 
| 48 | 
            +
                  delivery_info, _, content = q.pop(:manual_ack => true)
         | 
| 49 49 |  | 
| 50 50 | 
             
                  subject.nack(delivery_info.delivery_tag, true, true)
         | 
| 51 51 | 
             
                  sleep(0.5)
         | 
| @@ -64,7 +64,7 @@ q = subject.queue("bunny.basic.nack.with-requeue-true-multi-true", :exclusive => | |
| 64 64 | 
             
                  x.publish("bunneth", :routing_key => q.name)
         | 
| 65 65 | 
             
                  sleep(0.25)
         | 
| 66 66 | 
             
                  q.message_count.should == 1
         | 
| 67 | 
            -
                  _, _, content = q.pop(: | 
| 67 | 
            +
                  _, _, content = q.pop(:manual_ack => true)
         | 
| 68 68 |  | 
| 69 69 | 
             
                  subject.on_error do |ch, channel_close|
         | 
| 70 70 | 
             
                    @channel_close = channel_close
         | 
| @@ -20,7 +20,7 @@ describe Bunny::Channel, "#reject" do | |
| 20 20 | 
             
                  x.publish("bunneth", :routing_key => q.name)
         | 
| 21 21 | 
             
                  sleep(0.5)
         | 
| 22 22 | 
             
                  q.message_count.should == 1
         | 
| 23 | 
            -
                  delivery_info, _, _ = q.pop(: | 
| 23 | 
            +
                  delivery_info, _, _ = q.pop(:manual_ack => true)
         | 
| 24 24 |  | 
| 25 25 | 
             
                  ch.reject(delivery_info.delivery_tag, true)
         | 
| 26 26 | 
             
                  sleep(0.5)
         | 
| @@ -39,7 +39,7 @@ describe Bunny::Channel, "#reject" do | |
| 39 39 | 
             
                  x.publish("bunneth", :routing_key => q.name)
         | 
| 40 40 | 
             
                  sleep(0.5)
         | 
| 41 41 | 
             
                  q.message_count.should == 1
         | 
| 42 | 
            -
                  delivery_info, _, _ = q.pop(: | 
| 42 | 
            +
                  delivery_info, _, _ = q.pop(:manual_ack => true)
         | 
| 43 43 |  | 
| 44 44 | 
             
                  ch.reject(delivery_info.delivery_tag, false)
         | 
| 45 45 | 
             
                  sleep(0.5)
         | 
| @@ -59,7 +59,7 @@ describe Bunny::Channel, "#reject" do | |
| 59 59 | 
             
                  x.publish("bunneth", :routing_key => q.name)
         | 
| 60 60 | 
             
                  sleep(0.25)
         | 
| 61 61 | 
             
                  q.message_count.should == 1
         | 
| 62 | 
            -
                  _, _, content = q.pop(: | 
| 62 | 
            +
                  _, _, content = q.pop(:manual_ack => true)
         | 
| 63 63 |  | 
| 64 64 | 
             
                  ch.on_error do |ch, channel_close|
         | 
| 65 65 | 
             
                    @channel_close = channel_close
         | 
| @@ -8,7 +8,11 @@ unless ENV["CI"] | |
| 8 8 |  | 
| 9 9 | 
             
                def close_all_connections!
         | 
| 10 10 | 
             
                  http_client.list_connections.each do |conn_info|
         | 
| 11 | 
            -
                     | 
| 11 | 
            +
                    begin
         | 
| 12 | 
            +
                      http_client.close_connection(conn_info.name)
         | 
| 13 | 
            +
                    rescue Bunny::ConnectionForced
         | 
| 14 | 
            +
                      # This is not a problem, but the specs intermittently believe it is.
         | 
| 15 | 
            +
                    end
         | 
| 12 16 | 
             
                  end
         | 
| 13 17 | 
             
                end
         | 
| 14 18 |  | 
| @@ -25,6 +29,29 @@ unless ENV["CI"] | |
| 25 29 | 
             
                  end
         | 
| 26 30 | 
             
                end
         | 
| 27 31 |  | 
| 32 | 
            +
                def with_open_multi_host( c = Bunny.new( :hosts => ["127.0.0.1", "localhost"],
         | 
| 33 | 
            +
                                                         :network_recovery_interval => 0.2,
         | 
| 34 | 
            +
                                                         :recover_from_connection_close => true), &block)
         | 
| 35 | 
            +
                  begin
         | 
| 36 | 
            +
                    c.start
         | 
| 37 | 
            +
                    block.call(c)
         | 
| 38 | 
            +
                  ensure
         | 
| 39 | 
            +
                    c.close
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def with_open_multi_broken_host( c = Bunny.new( :hosts => ["broken", "127.0.0.1", "localhost"],
         | 
| 44 | 
            +
                                                         :hosts_shuffle_strategy => Proc.new { |hosts| hosts }, # We do not shuffle for these tests so we always hit the broken host
         | 
| 45 | 
            +
                                                         :network_recovery_interval => 0.2,
         | 
| 46 | 
            +
                                                         :recover_from_connection_close => true), &block)
         | 
| 47 | 
            +
                  begin
         | 
| 48 | 
            +
                    c.start
         | 
| 49 | 
            +
                    block.call(c)
         | 
| 50 | 
            +
                  ensure
         | 
| 51 | 
            +
                    c.close
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 28 55 | 
             
                def ensure_queue_recovery(ch, q)
         | 
| 29 56 | 
             
                  q.purge
         | 
| 30 57 | 
             
                  x = ch.default_exchange
         | 
| @@ -66,7 +93,29 @@ unless ENV["CI"] | |
| 66 93 | 
             
                  end
         | 
| 67 94 | 
             
                end
         | 
| 68 95 |  | 
| 69 | 
            -
                it " | 
| 96 | 
            +
                it "reconnects after grace period (with multiple hosts)" do
         | 
| 97 | 
            +
                  with_open_multi_host do |c|
         | 
| 98 | 
            +
                    close_all_connections!
         | 
| 99 | 
            +
                    sleep 0.1
         | 
| 100 | 
            +
                    c.should_not be_open
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                    wait_for_recovery
         | 
| 103 | 
            +
                    c.should be_open
         | 
| 104 | 
            +
                  end
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                it "reconnects after grace period (with multiple hosts, including a broken one)" do
         | 
| 108 | 
            +
                  with_open_multi_broken_host do |c|
         | 
| 109 | 
            +
                    close_all_connections!
         | 
| 110 | 
            +
                    sleep 0.1
         | 
| 111 | 
            +
                    c.should_not be_open
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                    wait_for_recovery
         | 
| 114 | 
            +
                    c.should be_open
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                it "recovers channels" do
         | 
| 70 119 | 
             
                  with_open do |c|
         | 
| 71 120 | 
             
                    ch1 = c.create_channel
         | 
| 72 121 | 
             
                    ch2 = c.create_channel
         | 
| @@ -80,6 +129,34 @@ unless ENV["CI"] | |
| 80 129 | 
             
                  end
         | 
| 81 130 | 
             
                end
         | 
| 82 131 |  | 
| 132 | 
            +
                it "recovers channels (with multiple hosts)" do
         | 
| 133 | 
            +
                  with_open_multi_host do |c|
         | 
| 134 | 
            +
                    ch1 = c.create_channel
         | 
| 135 | 
            +
                    ch2 = c.create_channel
         | 
| 136 | 
            +
                    close_all_connections!
         | 
| 137 | 
            +
                    sleep 0.1
         | 
| 138 | 
            +
                    c.should_not be_open
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                    wait_for_recovery
         | 
| 141 | 
            +
                    ch1.should be_open
         | 
| 142 | 
            +
                    ch2.should be_open
         | 
| 143 | 
            +
                  end
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                it "recovers channels (with multiple hosts, including a broken one)" do
         | 
| 147 | 
            +
                  with_open_multi_broken_host do |c|
         | 
| 148 | 
            +
                    ch1 = c.create_channel
         | 
| 149 | 
            +
                    ch2 = c.create_channel
         | 
| 150 | 
            +
                    close_all_connections!
         | 
| 151 | 
            +
                    sleep 0.1
         | 
| 152 | 
            +
                    c.should_not be_open
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                    wait_for_recovery
         | 
| 155 | 
            +
                    ch1.should be_open
         | 
| 156 | 
            +
                    ch2.should be_open
         | 
| 157 | 
            +
                  end
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 83 160 | 
             
                it "recovers basic.qos prefetch setting" do
         | 
| 84 161 | 
             
                  with_open do |c|
         | 
| 85 162 | 
             
                    ch = c.create_channel
         |