bunny 2.15.0 → 2.19.0
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/README.md +30 -12
- data/lib/bunny/channel.rb +2 -2
- data/lib/bunny/reader_loop.rb +11 -11
- data/lib/bunny/session.rb +32 -9
- data/lib/bunny/transport.rb +12 -11
- data/lib/bunny/version.rb +1 -1
- data/spec/higher_level_api/integration/basic_consume_spec.rb +14 -6
- data/spec/higher_level_api/integration/connection_spec.rb +26 -0
- data/spec/higher_level_api/integration/tls_connection_spec.rb +25 -32
- data/spec/issues/issue609_spec.rb +84 -0
- data/spec/lower_level_api/integration/basic_cancel_spec.rb +1 -1
- data/spec/lower_level_api/integration/basic_consume_spec.rb +8 -8
- metadata +28 -87
- data/.github/ISSUE_TEMPLATE.md +0 -18
- data/.gitignore +0 -28
- data/.rspec +0 -1
- data/.travis.yml +0 -33
- data/.yardopts +0 -8
- data/CONTRIBUTING.md +0 -132
- data/ChangeLog.md +0 -2084
- data/Gemfile +0 -55
- data/LICENSE +0 -21
- data/Rakefile +0 -54
- data/benchmarks/basic_publish/with_128K_messages.rb +0 -35
- data/benchmarks/basic_publish/with_1k_messages.rb +0 -35
- data/benchmarks/basic_publish/with_4K_messages.rb +0 -35
- data/benchmarks/basic_publish/with_64K_messages.rb +0 -35
- data/benchmarks/channel_open.rb +0 -28
- data/benchmarks/mutex_and_monitor.rb +0 -42
- data/benchmarks/queue_declare.rb +0 -29
- data/benchmarks/queue_declare_and_bind.rb +0 -29
- data/benchmarks/queue_declare_bind_and_delete.rb +0 -29
- data/benchmarks/synchronized_sorted_set.rb +0 -53
- data/benchmarks/write_vs_write_nonblock.rb +0 -49
- data/bunny.gemspec +0 -34
- data/docker/Dockerfile +0 -24
- data/docker/apt/preferences.d/erlang +0 -3
- data/docker/apt/sources.list.d/bintray.rabbitmq.list +0 -2
- data/docker/docker-entrypoint.sh +0 -26
- data/docker/rabbitmq.conf +0 -29
- data/docker-compose.yml +0 -28
- data/examples/connection/authentication_failure.rb +0 -16
- data/examples/connection/automatic_recovery_with_basic_get.rb +0 -40
- data/examples/connection/automatic_recovery_with_client_named_queues.rb +0 -36
- data/examples/connection/automatic_recovery_with_multiple_consumers.rb +0 -46
- data/examples/connection/automatic_recovery_with_republishing.rb +0 -109
- data/examples/connection/automatic_recovery_with_server_named_queues.rb +0 -35
- data/examples/connection/channel_level_exception.rb +0 -27
- data/examples/connection/disabled_automatic_recovery.rb +0 -34
- data/examples/connection/heartbeat.rb +0 -17
- data/examples/connection/manually_reconnecting_consumer.rb +0 -23
- data/examples/connection/manually_reconnecting_publisher.rb +0 -28
- data/examples/connection/unknown_host.rb +0 -16
- data/examples/consumers/high_and_low_priority.rb +0 -50
- data/examples/guides/exchanges/direct_exchange_routing.rb +0 -36
- data/examples/guides/exchanges/fanout_exchange_routing.rb +0 -28
- data/examples/guides/exchanges/headers_exchange_routing.rb +0 -31
- data/examples/guides/exchanges/mandatory_messages.rb +0 -30
- data/examples/guides/extensions/alternate_exchange.rb +0 -30
- data/examples/guides/extensions/basic_nack.rb +0 -33
- data/examples/guides/extensions/connection_blocked.rb +0 -35
- data/examples/guides/extensions/consumer_cancellation_notification.rb +0 -39
- data/examples/guides/extensions/dead_letter_exchange.rb +0 -32
- data/examples/guides/extensions/exchange_to_exchange_bindings.rb +0 -29
- data/examples/guides/extensions/per_message_ttl.rb +0 -36
- data/examples/guides/extensions/per_queue_message_ttl.rb +0 -36
- data/examples/guides/extensions/publisher_confirms.rb +0 -28
- data/examples/guides/extensions/queue_lease.rb +0 -26
- data/examples/guides/extensions/sender_selected_distribution.rb +0 -32
- data/examples/guides/getting_started/blabbr.rb +0 -27
- data/examples/guides/getting_started/hello_world.rb +0 -22
- data/examples/guides/getting_started/weathr.rb +0 -49
- data/examples/guides/queues/one_off_consumer.rb +0 -25
- data/examples/guides/queues/redeliveries.rb +0 -81
- data/profiling/basic_publish/with_4K_messages.rb +0 -33
- data/repl +0 -3
- data/spec/tls/ca_certificate.pem +0 -29
- data/spec/tls/ca_key.pem +0 -52
- data/spec/tls/client_certificate.pem +0 -29
- data/spec/tls/client_key.pem +0 -51
- data/spec/tls/generate-server-cert.sh +0 -8
- data/spec/tls/server-openssl.cnf +0 -10
- data/spec/tls/server.csr +0 -16
- data/spec/tls/server_certificate.pem +0 -29
- data/spec/tls/server_key.pem +0 -51
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d6de535f1d386dbf46fd89a733c1c44915280af55c3cc3cc56467abe0ead9c24
         | 
| 4 | 
            +
              data.tar.gz: 6048aea84078fb8995718ed774d9a3956dc91645b24c09382cd54283b444aabe
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: b3575710f81dabf6c116c92c4ac1807a29f0c0bcd1bd5fb35ae1fd9dd468df193efac49d0ad5e77ef04ecc53e97b9b4e13e70f4207972ba0c2335c28afcd6c9b
         | 
| 7 | 
            +
              data.tar.gz: 8b90dd4da7dab28b529e78cf1282656ca1904432b1017ee5574545c1972315f975d175c718481372604b61796e9ae56b293a342dcba800fa0929e4b80cd7a3c4
         | 
    
        data/README.md
    CHANGED
    
    | @@ -43,12 +43,11 @@ Specific examples: | |
| 43 43 | 
             
               Web applications that display that information in the real time.
         | 
| 44 44 |  | 
| 45 45 |  | 
| 46 | 
            -
             | 
| 47 46 | 
             
            ## Supported Ruby Versions
         | 
| 48 47 |  | 
| 49 48 | 
             
            Modern Bunny versions support
         | 
| 50 49 |  | 
| 51 | 
            -
             * CRuby 2. | 
| 50 | 
            +
             * CRuby 2.5 through 3.0 (inclusive)
         | 
| 52 51 |  | 
| 53 52 | 
             
            Bunny works sufficiently well on JRuby but there are known
         | 
| 54 53 | 
             
            JRuby bugs in versions prior to JRuby 9000 that cause high CPU burn. JRuby users should
         | 
| @@ -71,10 +70,8 @@ a stable public API. | |
| 71 70 | 
             
            Change logs per release series:
         | 
| 72 71 |  | 
| 73 72 | 
             
             * [master](https://github.com/ruby-amqp/bunny/blob/master/ChangeLog.md)
         | 
| 74 | 
            -
             * [2. | 
| 75 | 
            -
             * [2. | 
| 76 | 
            -
             * [2.12.x](https://github.com/ruby-amqp/bunny/blob/2.12.x-stable/ChangeLog.md)
         | 
| 77 | 
            -
             * [2.11.x](https://github.com/ruby-amqp/bunny/blob/2.11.x-stable/ChangeLog.md)
         | 
| 73 | 
            +
             * [2.18.x](https://github.com/ruby-amqp/bunny/blob/2.18.x-stable/ChangeLog.md)
         | 
| 74 | 
            +
             * [2.17.x](https://github.com/ruby-amqp/bunny/blob/2.17.x-stable/ChangeLog.md)
         | 
| 78 75 |  | 
| 79 76 |  | 
| 80 77 |  | 
| @@ -97,7 +94,7 @@ gem install bunny | |
| 97 94 | 
             
            To use Bunny in a project managed with Bundler:
         | 
| 98 95 |  | 
| 99 96 | 
             
            ``` ruby
         | 
| 100 | 
            -
            gem "bunny", ">= 2. | 
| 97 | 
            +
            gem "bunny", ">= 2.18.0"
         | 
| 101 98 | 
             
            ```
         | 
| 102 99 |  | 
| 103 100 |  | 
| @@ -117,20 +114,31 @@ conn.start | |
| 117 114 |  | 
| 118 115 | 
             
            # open a channel
         | 
| 119 116 | 
             
            ch = conn.create_channel
         | 
| 117 | 
            +
            ch.confirm_select
         | 
| 120 118 |  | 
| 121 119 | 
             
            # declare a queue
         | 
| 122 120 | 
             
            q  = ch.queue("test1")
         | 
| 121 | 
            +
            q.subscribe(manual_ack: true) do |delivery_info, metadata, payload|
         | 
| 122 | 
            +
              puts "This is the message: #{payload}"
         | 
| 123 | 
            +
              # acknowledge the delivery so that RabbitMQ can mark it for deletion
         | 
| 124 | 
            +
              ch.ack(delivery_info.delivery_tag)
         | 
| 125 | 
            +
            end
         | 
| 123 126 |  | 
| 124 127 | 
             
            # publish a message to the default exchange which then gets routed to this queue
         | 
| 125 128 | 
             
            q.publish("Hello, everybody!")
         | 
| 126 129 |  | 
| 127 | 
            -
            #  | 
| 128 | 
            -
             | 
| 130 | 
            +
            # await confirmations from RabbitMQ, see
         | 
| 131 | 
            +
            # https://www.rabbitmq.com/publishers.html#data-safety for details
         | 
| 132 | 
            +
            ch.wait_for_confirms
         | 
| 133 | 
            +
             | 
| 134 | 
            +
            # give the above consumer some time consume the delivery and print out the message
         | 
| 135 | 
            +
            sleep 1
         | 
| 129 136 |  | 
| 130 | 
            -
            puts " | 
| 137 | 
            +
            puts "Done"
         | 
| 131 138 |  | 
| 139 | 
            +
            ch.close
         | 
| 132 140 | 
             
            # close the connection
         | 
| 133 | 
            -
            conn. | 
| 141 | 
            +
            conn.close
         | 
| 134 142 | 
             
            ```
         | 
| 135 143 |  | 
| 136 144 |  | 
| @@ -142,7 +150,7 @@ For a 15 minute tutorial using more practical examples, see [Getting Started wit | |
| 142 150 |  | 
| 143 151 | 
             
            ### Guides
         | 
| 144 152 |  | 
| 145 | 
            -
             | 
| 153 | 
            +
            Bunny documentation guides are available at [rubybunny.info](http://rubybunny.info):
         | 
| 146 154 |  | 
| 147 155 | 
             
             * [Queues and Consumers](http://rubybunny.info/articles/queues.html)
         | 
| 148 156 | 
             
             * [Exchanges and Publishers](http://rubybunny.info/articles/exchanges.html)
         | 
| @@ -154,6 +162,16 @@ Other documentation guides are available at [rubybunny.info](http://rubybunny.in | |
| 154 162 | 
             
             * [Using RabbitMQ Extensions with Bunny](http://rubybunny.info/articles/extensions.html)
         | 
| 155 163 | 
             
             * [Durability and Related Matters](http://rubybunny.info/articles/durability.html)
         | 
| 156 164 |  | 
| 165 | 
            +
            Some highly relevant RabbitMQ documentation guides:
         | 
| 166 | 
            +
             | 
| 167 | 
            +
             * [Connections](https://www.rabbitmq.com/connections.html)
         | 
| 168 | 
            +
             * [Channels](https://www.rabbitmq.com/channels.html)
         | 
| 169 | 
            +
             * [Queues](https://www.rabbitmq.com/queues.html)
         | 
| 170 | 
            +
             * [Publishers](https://www.rabbitmq.com/publishers.html)
         | 
| 171 | 
            +
             * [Consumers](https://www.rabbitmq.com/consumers.html)
         | 
| 172 | 
            +
             * Data safety: publisher and consumer [Confirmations](https://www.rabbitmq.com/confirms.html)
         | 
| 173 | 
            +
             * [Production Checklist](https://www.rabbitmq.com/production-checklist.html)
         | 
| 174 | 
            +
             | 
| 157 175 | 
             
            ### API Reference
         | 
| 158 176 |  | 
| 159 177 | 
             
            [Bunny API Reference](http://reference.rubybunny.info/).
         | 
    
        data/lib/bunny/channel.rb
    CHANGED
    
    | @@ -1156,7 +1156,7 @@ module Bunny | |
| 1156 1156 |  | 
| 1157 1157 | 
             
                # @group Exchange operations (exchange.*)
         | 
| 1158 1158 |  | 
| 1159 | 
            -
                # Declares a exchange using  | 
| 1159 | 
            +
                # Declares a exchange using exchange.declare AMQP 0.9.1 method.
         | 
| 1160 1160 | 
             
                #
         | 
| 1161 1161 | 
             
                # @param [String] name The name of the exchange. Note that LF and CR characters
         | 
| 1162 1162 | 
             
                #                       will be stripped from the value.
         | 
| @@ -1789,7 +1789,7 @@ module Bunny | |
| 1789 1789 | 
             
                # @private
         | 
| 1790 1790 | 
             
                def handle_ack_or_nack(delivery_tag_before_offset, multiple, nack)
         | 
| 1791 1791 | 
             
                  delivery_tag          = delivery_tag_before_offset + @delivery_tag_offset
         | 
| 1792 | 
            -
                  confirmed_range_start = multiple ? @delivery_tag_offset +  | 
| 1792 | 
            +
                  confirmed_range_start = multiple ? @delivery_tag_offset + @unconfirmed_set.min : delivery_tag
         | 
| 1793 1793 | 
             
                  confirmed_range_end   = delivery_tag
         | 
| 1794 1794 | 
             
                  confirmed_range       = (confirmed_range_start..confirmed_range_end)
         | 
| 1795 1795 |  | 
    
        data/lib/bunny/reader_loop.rb
    CHANGED
    
    | @@ -9,17 +9,17 @@ module Bunny | |
| 9 9 | 
             
              # @private
         | 
| 10 10 | 
             
              class ReaderLoop
         | 
| 11 11 |  | 
| 12 | 
            -
                def initialize(transport, session,  | 
| 13 | 
            -
                  @transport | 
| 14 | 
            -
                  @session | 
| 15 | 
            -
                  @ | 
| 16 | 
            -
                  @logger | 
| 12 | 
            +
                def initialize(transport, session, session_error_handler)
         | 
| 13 | 
            +
                  @transport             = transport
         | 
| 14 | 
            +
                  @session               = session
         | 
| 15 | 
            +
                  @session_error_handler = session_error_handler
         | 
| 16 | 
            +
                  @logger                = @session.logger
         | 
| 17 17 |  | 
| 18 | 
            -
                  @mutex | 
| 18 | 
            +
                  @mutex                 = Mutex.new
         | 
| 19 19 |  | 
| 20 | 
            -
                  @stopping | 
| 21 | 
            -
                  @stopped | 
| 22 | 
            -
                  @network_is_down | 
| 20 | 
            +
                  @stopping              = false
         | 
| 21 | 
            +
                  @stopped               = false
         | 
| 22 | 
            +
                  @network_is_down       = false
         | 
| 23 23 | 
             
                end
         | 
| 24 24 |  | 
| 25 25 |  | 
| @@ -47,7 +47,7 @@ module Bunny | |
| 47 47 | 
             
                        @session.handle_network_failure(e)
         | 
| 48 48 | 
             
                      else
         | 
| 49 49 | 
             
                        log_exception(e)
         | 
| 50 | 
            -
                        @ | 
| 50 | 
            +
                        @session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
         | 
| 51 51 | 
             
                      end
         | 
| 52 52 | 
             
                    rescue ShutdownSignal => _
         | 
| 53 53 | 
             
                      @mutex.synchronize { @stopping = true }
         | 
| @@ -58,7 +58,7 @@ module Bunny | |
| 58 58 | 
             
                        log_exception(e)
         | 
| 59 59 |  | 
| 60 60 | 
             
                        @network_is_down = true
         | 
| 61 | 
            -
                        @ | 
| 61 | 
            +
                        @session_error_handler.raise(Bunny::NetworkFailure.new("caught an unexpected exception in the network loop: #{e.message}", e))
         | 
| 62 62 | 
             
                      end
         | 
| 63 63 | 
             
                    rescue Errno::EBADF => _ebadf
         | 
| 64 64 | 
             
                      break if terminate?
         | 
    
        data/lib/bunny/session.rb
    CHANGED
    
    | @@ -89,6 +89,7 @@ module Bunny | |
| 89 89 | 
             
                # @return [Integer] Timeout for blocking protocol operations (queue.declare, queue.bind, etc), in milliseconds. Default is 15000.
         | 
| 90 90 | 
             
                attr_reader :continuation_timeout
         | 
| 91 91 | 
             
                attr_reader :network_recovery_interval
         | 
| 92 | 
            +
                attr_reader :connection_name
         | 
| 92 93 | 
             
                attr_accessor :socket_configurator
         | 
| 93 94 |  | 
| 94 95 | 
             
                # @param [String, Hash] connection_string_or_opts Connection string or a hash of connection options
         | 
| @@ -123,10 +124,14 @@ module Bunny | |
| 123 124 | 
             
                # @option connection_string_or_opts [Boolean] :automatically_recover (true) Should automatically recover from network failures?
         | 
| 124 125 | 
             
                # @option connection_string_or_opts [Integer] :recovery_attempts (nil) Max number of recovery attempts, nil means forever
         | 
| 125 126 | 
             
                # @option connection_string_or_opts [Integer] :reset_recovery_attempts_after_reconnection (true) Should recovery attempt counter be reset after successful reconnection? When set to false, the attempt counter will last through the entire lifetime of the connection object.
         | 
| 127 | 
            +
                # @option connection_string_or_opts [Proc] :recovery_attempt_started (nil) Will be called before every connection recovery attempt
         | 
| 128 | 
            +
                # @option connection_string_or_opts [Proc] :recovery_completed (nil) Will be called after successful connection recovery
         | 
| 126 129 | 
             
                # @option connection_string_or_opts [Boolean] :recover_from_connection_close (true) Should this connection recover after receiving a server-sent connection.close (e.g. connection was force closed)?
         | 
| 130 | 
            +
                # @option connection_string_or_opts [Object] :session_error_handler (Thread.current) Object which responds to #raise that will act as a session error handler. Defaults to Thread.current, which will raise asynchronous exceptions in the thread that created the session.
         | 
| 127 131 | 
             
                #
         | 
| 128 132 | 
             
                # @option optz [String] :auth_mechanism ("PLAIN") Authentication mechanism, PLAIN or EXTERNAL
         | 
| 129 133 | 
             
                # @option optz [String] :locale ("PLAIN") Locale RabbitMQ should use
         | 
| 134 | 
            +
                # @option optz [String] :connection_name (nil) Client-provided connection name, if any. Note that the value returned does not uniquely identify a connection and cannot be used as a connection identifier in HTTP API requests.
         | 
| 130 135 | 
             
                #
         | 
| 131 136 | 
             
                # @see http://rubybunny.info/articles/connecting.html Connecting to RabbitMQ guide
         | 
| 132 137 | 
             
                # @see http://rubybunny.info/articles/tls.html TLS/SSL guide
         | 
| @@ -169,7 +174,7 @@ module Bunny | |
| 169 174 | 
             
                  @automatically_recover = if opts[:automatically_recover].nil? && opts[:automatic_recovery].nil?
         | 
| 170 175 | 
             
                                             true
         | 
| 171 176 | 
             
                                           else
         | 
| 172 | 
            -
                                             opts[:automatically_recover]  | 
| 177 | 
            +
                                             opts[:automatically_recover] | opts[:automatic_recovery]
         | 
| 173 178 | 
             
                                           end
         | 
| 174 179 | 
             
                  @recovering_from_network_failure = false
         | 
| 175 180 | 
             
                  @max_recovery_attempts = opts[:recovery_attempts]
         | 
| @@ -197,7 +202,9 @@ module Bunny | |
| 197 202 | 
             
                  @client_heartbeat   = self.heartbeat_from(opts)
         | 
| 198 203 |  | 
| 199 204 | 
             
                  client_props         = opts[:properties] || opts[:client_properties] || {}
         | 
| 205 | 
            +
                  @connection_name     = client_props[:connection_name] || opts[:connection_name]
         | 
| 200 206 | 
             
                  @client_properties   = DEFAULT_CLIENT_PROPERTIES.merge(client_props)
         | 
| 207 | 
            +
                                                                  .merge(connection_name: connection_name)
         | 
| 201 208 | 
             
                  @mechanism           = normalize_auth_mechanism(opts.fetch(:auth_mechanism, "PLAIN"))
         | 
| 202 209 | 
             
                  @credentials_encoder = credentials_encoder_for(@mechanism)
         | 
| 203 210 | 
             
                  @locale              = @opts.fetch(:locale, DEFAULT_LOCALE)
         | 
| @@ -213,9 +220,11 @@ module Bunny | |
| 213 220 | 
             
                  @address_index_mutex = @mutex_impl.new
         | 
| 214 221 |  | 
| 215 222 | 
             
                  @channels            = Hash.new
         | 
| 216 | 
            -
                  @recovery_completed = opts[:recovery_completed]
         | 
| 217 223 |  | 
| 218 | 
            -
                  @ | 
| 224 | 
            +
                  @recovery_attempt_started = opts[:recovery_attempt_started]
         | 
| 225 | 
            +
                  @recovery_completed       = opts[:recovery_completed]
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                  @session_error_handler = opts.fetch(:session_error_handler, Thread.current)
         | 
| 219 228 |  | 
| 220 229 | 
             
                  self.reset_continuations
         | 
| 221 230 | 
             
                  self.initialize_transport
         | 
| @@ -528,6 +537,18 @@ module Bunny | |
| 528 537 | 
             
                  end
         | 
| 529 538 | 
             
                end
         | 
| 530 539 |  | 
| 540 | 
            +
                # Defines a callable (e.g. a block) that will be called
         | 
| 541 | 
            +
                # before every connection recovery attempt.
         | 
| 542 | 
            +
                def before_recovery_attempt_starts(&block)
         | 
| 543 | 
            +
                  @recovery_attempt_started = block
         | 
| 544 | 
            +
                end
         | 
| 545 | 
            +
             | 
| 546 | 
            +
                # Defines a callable (e.g. a block) that will be called
         | 
| 547 | 
            +
                # after successful connection recovery.
         | 
| 548 | 
            +
                def after_recovery_completed(&block)
         | 
| 549 | 
            +
                  @recovery_completed = block
         | 
| 550 | 
            +
                end
         | 
| 551 | 
            +
             | 
| 531 552 |  | 
| 532 553 | 
             
                #
         | 
| 533 554 | 
             
                # Implementation
         | 
| @@ -745,6 +766,7 @@ module Bunny | |
| 745 766 | 
             
                def recover_from_network_failure
         | 
| 746 767 | 
             
                  sleep @network_recovery_interval
         | 
| 747 768 | 
             
                  @logger.debug "Will attempt connection recovery..."
         | 
| 769 | 
            +
                  notify_of_recovery_attempt_start
         | 
| 748 770 |  | 
| 749 771 | 
             
                  self.initialize_transport
         | 
| 750 772 |  | 
| @@ -818,8 +840,9 @@ module Bunny | |
| 818 840 | 
             
                  end
         | 
| 819 841 | 
             
                end
         | 
| 820 842 |  | 
| 821 | 
            -
                 | 
| 822 | 
            -
             | 
| 843 | 
            +
                # @private
         | 
| 844 | 
            +
                def notify_of_recovery_attempt_start
         | 
| 845 | 
            +
                  @recovery_attempt_started.call if @recovery_attempt_started
         | 
| 823 846 | 
             
                end
         | 
| 824 847 |  | 
| 825 848 | 
             
                # @private
         | 
| @@ -862,7 +885,7 @@ module Bunny | |
| 862 885 |  | 
| 863 886 | 
             
                  clean_up_on_shutdown
         | 
| 864 887 | 
             
                  if threaded?
         | 
| 865 | 
            -
                    @ | 
| 888 | 
            +
                    @session_error_handler.raise(@last_connection_error)
         | 
| 866 889 | 
             
                  else
         | 
| 867 890 | 
             
                    raise @last_connection_error
         | 
| 868 891 | 
             
                  end
         | 
| @@ -1019,7 +1042,7 @@ module Bunny | |
| 1019 1042 |  | 
| 1020 1043 | 
             
                # @private
         | 
| 1021 1044 | 
             
                def reader_loop
         | 
| 1022 | 
            -
                  @reader_loop ||= ReaderLoop.new(@transport, self,  | 
| 1045 | 
            +
                  @reader_loop ||= ReaderLoop.new(@transport, self, @session_error_handler)
         | 
| 1023 1046 | 
             
                end
         | 
| 1024 1047 |  | 
| 1025 1048 | 
             
                # @private
         | 
| @@ -1282,7 +1305,7 @@ module Bunny | |
| 1282 1305 | 
             
                      end
         | 
| 1283 1306 |  | 
| 1284 1307 | 
             
                      if threaded?
         | 
| 1285 | 
            -
                        @ | 
| 1308 | 
            +
                        @session_error_handler.raise(e)
         | 
| 1286 1309 | 
             
                      else
         | 
| 1287 1310 | 
             
                        raise e
         | 
| 1288 1311 | 
             
                      end
         | 
| @@ -1328,7 +1351,7 @@ module Bunny | |
| 1328 1351 | 
             
                    @transport = Transport.new(self,
         | 
| 1329 1352 | 
             
                                               host_from_address(address),
         | 
| 1330 1353 | 
             
                                               port_from_address(address),
         | 
| 1331 | 
            -
                                               @opts.merge(: | 
| 1354 | 
            +
                                               @opts.merge(:session_error_handler => @session_error_handler)
         | 
| 1332 1355 | 
             
                                              )
         | 
| 1333 1356 |  | 
| 1334 1357 | 
             
                    # Reset the cached progname for the logger only when no logger was provided
         | 
    
        data/lib/bunny/transport.rb
    CHANGED
    
    | @@ -35,7 +35,7 @@ module Bunny | |
| 35 35 |  | 
| 36 36 | 
             
                def initialize(session, host, port, opts)
         | 
| 37 37 | 
             
                  @session        = session
         | 
| 38 | 
            -
                  @ | 
| 38 | 
            +
                  @session_error_handler = opts[:session_error_handler]
         | 
| 39 39 | 
             
                  @host    = host
         | 
| 40 40 | 
             
                  @port    = port
         | 
| 41 41 | 
             
                  @opts    = opts
         | 
| @@ -146,7 +146,7 @@ module Bunny | |
| 146 146 | 
             
                      if @session.automatically_recover?
         | 
| 147 147 | 
             
                        @session.handle_network_failure(e)
         | 
| 148 148 | 
             
                      else
         | 
| 149 | 
            -
                        @ | 
| 149 | 
            +
                        @session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
         | 
| 150 150 | 
             
                      end
         | 
| 151 151 | 
             
                    end
         | 
| 152 152 | 
             
                  end
         | 
| @@ -170,7 +170,7 @@ module Bunny | |
| 170 170 | 
             
                      if @session.automatically_recover?
         | 
| 171 171 | 
             
                        @session.handle_network_failure(e)
         | 
| 172 172 | 
             
                      else
         | 
| 173 | 
            -
                        @ | 
| 173 | 
            +
                        @session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
         | 
| 174 174 | 
             
                      end
         | 
| 175 175 | 
             
                    end
         | 
| 176 176 | 
             
                  end
         | 
| @@ -188,7 +188,7 @@ module Bunny | |
| 188 188 | 
             
                    if @session.automatically_recover?
         | 
| 189 189 | 
             
                      @session.handle_network_failure(e)
         | 
| 190 190 | 
             
                    else
         | 
| 191 | 
            -
                      @ | 
| 191 | 
            +
                      @session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
         | 
| 192 192 | 
             
                    end
         | 
| 193 193 | 
             
                  end
         | 
| 194 194 | 
             
                end
         | 
| @@ -245,7 +245,7 @@ module Bunny | |
| 245 245 | 
             
                    if @session.automatically_recover?
         | 
| 246 246 | 
             
                      raise
         | 
| 247 247 | 
             
                    else
         | 
| 248 | 
            -
                      @ | 
| 248 | 
            +
                      @session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
         | 
| 249 249 | 
             
                    end
         | 
| 250 250 | 
             
                  end
         | 
| 251 251 | 
             
                end
         | 
| @@ -453,9 +453,9 @@ module Bunny | |
| 453 453 | 
             
                  end
         | 
| 454 454 | 
             
                end
         | 
| 455 455 |  | 
| 456 | 
            -
                def initialize_tls_context(ctx, opts={})
         | 
| 456 | 
            +
                def initialize_tls_context(ctx, opts = {})
         | 
| 457 457 | 
             
                  ctx.cert       = OpenSSL::X509::Certificate.new(@tls_certificate) if @tls_certificate
         | 
| 458 | 
            -
                  ctx.key        = OpenSSL::PKey | 
| 458 | 
            +
                  ctx.key        = OpenSSL::PKey.read(@tls_key) if @tls_key
         | 
| 459 459 | 
             
                  ctx.cert_store = if @tls_certificate_store
         | 
| 460 460 | 
             
                                     @tls_certificate_store
         | 
| 461 461 | 
             
                                   else
         | 
| @@ -463,8 +463,9 @@ module Bunny | |
| 463 463 | 
             
                                     @tls_ca_certificates = tls_ca_certificates_paths_from(opts)
         | 
| 464 464 | 
             
                                     initialize_tls_certificate_store(@tls_ca_certificates)
         | 
| 465 465 | 
             
                                   end
         | 
| 466 | 
            +
                  should_silence_warnings = opts.fetch(:tls_silence_warnings, false)
         | 
| 466 467 |  | 
| 467 | 
            -
                  if !@tls_certificate
         | 
| 468 | 
            +
                  if !@tls_certificate && !should_silence_warnings
         | 
| 468 469 | 
             
                    @logger.warn <<-MSG
         | 
| 469 470 | 
             
            Using TLS but no client certificate is provided. If RabbitMQ is configured to require & verify peer
         | 
| 470 471 | 
             
            certificate, connection will be rejected. Learn more at https://www.rabbitmq.com/ssl.html
         | 
| @@ -482,14 +483,14 @@ certificate, connection will be rejected. Learn more at https://www.rabbitmq.com | |
| 482 483 | 
             
                  @logger.debug { "Will use peer verification mode #{verify_mode}" }
         | 
| 483 484 | 
             
                  ctx.verify_mode = verify_mode
         | 
| 484 485 |  | 
| 485 | 
            -
                  if !@verify_peer
         | 
| 486 | 
            +
                  if !@verify_peer && !should_silence_warnings
         | 
| 486 487 | 
             
                    @logger.warn <<-MSG
         | 
| 487 488 | 
             
            Using TLS but peer hostname verification is disabled. This is convenient for local development
         | 
| 488 489 | 
             
            but prone to man-in-the-middle attacks. Please set verify_peer: true in production. Learn more at https://www.rabbitmq.com/ssl.html
         | 
| 489 490 | 
             
                    MSG
         | 
| 490 491 | 
             
                  end
         | 
| 491 492 |  | 
| 492 | 
            -
                  ssl_version = opts[:tls_protocol] || opts[:ssl_version]
         | 
| 493 | 
            +
                  ssl_version = opts[:tls_protocol] || opts[:ssl_version] || :TLSv1_2
         | 
| 493 494 | 
             
                  ctx.ssl_version = ssl_version if ssl_version
         | 
| 494 495 |  | 
| 495 496 | 
             
                  ctx
         | 
| @@ -501,7 +502,7 @@ but prone to man-in-the-middle attacks. Please set verify_peer: true in producti | |
| 501 502 | 
             
                  certs.each do |cert|
         | 
| 502 503 | 
             
                    # if it starts with / or C:/ then it's a file path that may or may not
         | 
| 503 504 | 
             
                    # exist (e.g. a default OpenSSL path). MK.
         | 
| 504 | 
            -
                    if File.readable?(cert) || cert =~  | 
| 505 | 
            +
                    if File.readable?(cert) || cert =~ /\A([a-z]:?)?\//i
         | 
| 505 506 | 
             
                      cert_files.push(cert)
         | 
| 506 507 | 
             
                    else
         | 
| 507 508 | 
             
                      cert_inlines.push(cert)
         | 
    
        data/lib/bunny/version.rb
    CHANGED
    
    
| @@ -62,8 +62,10 @@ describe Bunny::Queue, "#subscribe" do | |
| 62 62 | 
             
                      x.publish("hello", routing_key: queue_name)
         | 
| 63 63 | 
             
                    end
         | 
| 64 64 |  | 
| 65 | 
            -
                    sleep 1. | 
| 66 | 
            -
                     | 
| 65 | 
            +
                    sleep 1.5
         | 
| 66 | 
            +
                    100.times do |i|
         | 
| 67 | 
            +
                      expect(delivery_tags).to include(i + 1)
         | 
| 68 | 
            +
                    end
         | 
| 67 69 |  | 
| 68 70 | 
             
                    expect(ch.queue(queue_name, auto_delete: true, durable: false).message_count).to eq 0
         | 
| 69 71 |  | 
| @@ -95,7 +97,9 @@ describe Bunny::Queue, "#subscribe" do | |
| 95 97 | 
             
                    end
         | 
| 96 98 |  | 
| 97 99 | 
             
                    sleep 1.5
         | 
| 98 | 
            -
                     | 
| 100 | 
            +
                    100.times do |i|
         | 
| 101 | 
            +
                      expect(delivery_tags).to include(i + 1)
         | 
| 102 | 
            +
                    end
         | 
| 99 103 |  | 
| 100 104 | 
             
                    expect(ch.queue(queue_name, auto_delete: true, durable: false).message_count).to eq 0
         | 
| 101 105 |  | 
| @@ -305,8 +309,10 @@ describe Bunny::Queue, "#subscribe" do | |
| 305 309 | 
             
                      x.publish("hello", routing_key: queue_name)
         | 
| 306 310 | 
             
                    end
         | 
| 307 311 |  | 
| 308 | 
            -
                    sleep 1. | 
| 309 | 
            -
                     | 
| 312 | 
            +
                    sleep 1.5
         | 
| 313 | 
            +
                    100.times do |i|
         | 
| 314 | 
            +
                      expect(delivery_tags).to include(i + 1)
         | 
| 315 | 
            +
                    end
         | 
| 310 316 |  | 
| 311 317 | 
             
                    expect(ch.queue(queue_name, auto_delete: true, durable: false).message_count).to eq 0
         | 
| 312 318 |  | 
| @@ -338,7 +344,9 @@ describe Bunny::Queue, "#subscribe" do | |
| 338 344 | 
             
                    end
         | 
| 339 345 |  | 
| 340 346 | 
             
                    sleep 1.5
         | 
| 341 | 
            -
                     | 
| 347 | 
            +
                    100.times do |i|
         | 
| 348 | 
            +
                      expect(delivery_tags).to include(i + 1)
         | 
| 349 | 
            +
                    end
         | 
| 342 350 |  | 
| 343 351 | 
             
                    expect(ch.queue(queue_name, auto_delete: true, durable: false).message_count).to eq 0
         | 
| 344 352 |  | 
| @@ -560,4 +560,30 @@ describe Bunny::Session do | |
| 560 560 | 
             
                  described_class.new(logger: logger)
         | 
| 561 561 | 
             
                end
         | 
| 562 562 | 
             
              end
         | 
| 563 | 
            +
             | 
| 564 | 
            +
              context "initialized with a custom connection name" do
         | 
| 565 | 
            +
                it "uses provided connection name with default connection string" do
         | 
| 566 | 
            +
                  conn = Bunny.new(connection_name: 'test_name')
         | 
| 567 | 
            +
             | 
| 568 | 
            +
                  expect(conn.connection_name).to eq 'test_name'
         | 
| 569 | 
            +
                end
         | 
| 570 | 
            +
             | 
| 571 | 
            +
                it "uses provided connection name from client property hash" do
         | 
| 572 | 
            +
                  conn = Bunny.new(client_properties: {connection_name: 'cp/test_name'})
         | 
| 573 | 
            +
             | 
| 574 | 
            +
                  expect(conn.connection_name).to eq 'cp/test_name'
         | 
| 575 | 
            +
                end
         | 
| 576 | 
            +
             | 
| 577 | 
            +
                it "uses provided connection name with custom connection string" do
         | 
| 578 | 
            +
                  conn = Bunny.new('amqp://guest:guest@rabbitmq:5672', connection_name: 'test_name3')
         | 
| 579 | 
            +
             | 
| 580 | 
            +
                  expect(conn.connection_name).to eq 'test_name3'
         | 
| 581 | 
            +
                end
         | 
| 582 | 
            +
             | 
| 583 | 
            +
                it "uses provided connection name with hash options" do
         | 
| 584 | 
            +
                  conn = Bunny.new(user: 'user', password: 'p455w0rd', connection_name: 'test_name4')
         | 
| 585 | 
            +
             | 
| 586 | 
            +
                  expect(conn.connection_name).to eq 'test_name4'
         | 
| 587 | 
            +
                end
         | 
| 588 | 
            +
              end
         | 
| 563 589 | 
             
            end
         | 
| @@ -39,20 +39,6 @@ def local_hostname | |
| 39 39 | 
             
              ENV.fetch("BUNNY_RABBITMQ_HOSTNAME", "localhost")
         | 
| 40 40 | 
             
            end
         | 
| 41 41 |  | 
| 42 | 
            -
            def no_tls12_supported?
         | 
| 43 | 
            -
              not tls12_supported?
         | 
| 44 | 
            -
            end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
            def tls12_supported?
         | 
| 47 | 
            -
              begin
         | 
| 48 | 
            -
                ctx = OpenSSL::SSL::SSLContext.new
         | 
| 49 | 
            -
                ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
         | 
| 50 | 
            -
                true
         | 
| 51 | 
            -
              rescue
         | 
| 52 | 
            -
                false
         | 
| 53 | 
            -
              end
         | 
| 54 | 
            -
            end
         | 
| 55 | 
            -
             | 
| 56 42 | 
             
            context "initialized with tls: true", skip: ENV["CI"] do
         | 
| 57 43 | 
             
              let(:subject) do
         | 
| 58 44 | 
             
                Bunny.new(
         | 
| @@ -102,6 +88,7 @@ describe "TLS connection to RabbitMQ with client certificates", skip: ENV["CI"] | |
| 102 88 | 
             
                  password: "bunny_password",
         | 
| 103 89 | 
             
                  vhost: "bunny_testbed",
         | 
| 104 90 | 
             
                  tls: true,
         | 
| 91 | 
            +
                  tls_protocol: :TLSv1_2,
         | 
| 105 92 | 
             
                  tls_cert: "#{CERTIFICATE_DIR}/client_certificate.pem",
         | 
| 106 93 | 
             
                  tls_key: "#{CERTIFICATE_DIR}/client_key.pem",
         | 
| 107 94 | 
             
                  tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
         | 
| @@ -126,6 +113,7 @@ describe "TLS connection to RabbitMQ without client certificates", skip: ENV["CI | |
| 126 113 | 
             
                  password: "bunny_password",
         | 
| 127 114 | 
             
                  vhost: "bunny_testbed",
         | 
| 128 115 | 
             
                  tls: true,
         | 
| 116 | 
            +
                  tls_protocol: :TLSv1_2,
         | 
| 129 117 | 
             
                  tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
         | 
| 130 118 | 
             
                  verify_peer: false)
         | 
| 131 119 | 
             
                c.start
         | 
| @@ -143,6 +131,7 @@ end | |
| 143 131 | 
             
            describe "TLS connection to RabbitMQ with a connection string", skip: ENV["CI"] do
         | 
| 144 132 | 
             
              let(:subject) do
         | 
| 145 133 | 
             
                c = Bunny.new("amqps://bunny_gem:bunny_password@#{local_hostname()}/bunny_testbed",
         | 
| 134 | 
            +
                  tls_protocol: :TLSv1_2,
         | 
| 146 135 | 
             
                  tls_cert: "#{CERTIFICATE_DIR}/client_certificate.pem",
         | 
| 147 136 | 
             
                  tls_key: "#{CERTIFICATE_DIR}/client_key.pem",
         | 
| 148 137 | 
             
                  tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
         | 
| @@ -179,6 +168,7 @@ describe "TLS connection to RabbitMQ with a connection string and w/o client cer | |
| 179 168 | 
             
              let(:subject) do
         | 
| 180 169 | 
             
                c = Bunny.new("amqps://bunny_gem:bunny_password@#{local_hostname()}/bunny_testbed",
         | 
| 181 170 | 
             
                  tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
         | 
| 171 | 
            +
                  tls_protocol: :TLSv1_2,
         | 
| 182 172 | 
             
                  verify_peer: verify_peer)
         | 
| 183 173 | 
             
                c.start
         | 
| 184 174 | 
             
                c
         | 
| @@ -211,19 +201,13 @@ describe "TLS connection to RabbitMQ with a connection string and w/o client cer | |
| 211 201 | 
             
              end
         | 
| 212 202 | 
             
            end
         | 
| 213 203 |  | 
| 214 | 
            -
             | 
| 215 | 
            -
            describe "TLS connection to RabbitMQ with client certificates provided inline", skip: ENV["CI"] do
         | 
| 204 | 
            +
            describe "TLS connection to RabbitMQ w/o client certificate", skip: ENV["CI"] do
         | 
| 216 205 | 
             
              let(:subject) do
         | 
| 217 | 
            -
                c = Bunny.new(
         | 
| 218 | 
            -
                  hostname: local_hostname(),
         | 
| 219 | 
            -
                  username: "bunny_gem",
         | 
| 220 | 
            -
                  password: "bunny_password",
         | 
| 221 | 
            -
                  vhost: "bunny_testbed",
         | 
| 222 | 
            -
                  tls: true,
         | 
| 223 | 
            -
                  tls_cert: File.read("#{CERTIFICATE_DIR}/client_certificate.pem"),
         | 
| 224 | 
            -
                  tls_key: File.read("#{CERTIFICATE_DIR}/client_key.pem"),
         | 
| 206 | 
            +
                c = Bunny.new("amqps://bunny_gem:bunny_password@#{local_hostname()}/bunny_testbed",
         | 
| 225 207 | 
             
                  tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
         | 
| 226 | 
            -
                   | 
| 208 | 
            +
                  tls_protocol: :TLSv1_2,
         | 
| 209 | 
            +
                  verify_peer: false,
         | 
| 210 | 
            +
                  tls_silence_warnings: should_silence_warnings)
         | 
| 227 211 | 
             
                c.start
         | 
| 228 212 | 
             
                c
         | 
| 229 213 | 
             
              end
         | 
| @@ -232,10 +216,21 @@ describe "TLS connection to RabbitMQ with client certificates provided inline", | |
| 232 216 | 
             
                subject.close
         | 
| 233 217 | 
             
              end
         | 
| 234 218 |  | 
| 235 | 
            -
               | 
| 219 | 
            +
              context "TLS-related warnings are enabled" do
         | 
| 220 | 
            +
                let(:should_silence_warnings) { false }
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                include_examples "successful TLS connection"
         | 
| 223 | 
            +
              end
         | 
| 224 | 
            +
             | 
| 225 | 
            +
              context "TLS-related warnings are silenced" do
         | 
| 226 | 
            +
                let(:should_silence_warnings) { true }
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                include_examples "successful TLS connection"
         | 
| 229 | 
            +
              end
         | 
| 236 230 | 
             
            end
         | 
| 237 231 |  | 
| 238 | 
            -
             | 
| 232 | 
            +
             | 
| 233 | 
            +
            describe "TLS connection to RabbitMQ with client certificates provided inline", skip: ENV["CI"] do
         | 
| 239 234 | 
             
              let(:subject) do
         | 
| 240 235 | 
             
                c = Bunny.new(
         | 
| 241 236 | 
             
                  hostname: local_hostname(),
         | 
| @@ -243,8 +238,10 @@ describe "TLS connection to RabbitMQ with tls_version TLSv1.2 specified", skip: | |
| 243 238 | 
             
                  password: "bunny_password",
         | 
| 244 239 | 
             
                  vhost: "bunny_testbed",
         | 
| 245 240 | 
             
                  tls: true,
         | 
| 246 | 
            -
                   | 
| 241 | 
            +
                  tls_cert: File.read("#{CERTIFICATE_DIR}/client_certificate.pem"),
         | 
| 242 | 
            +
                  tls_key: File.read("#{CERTIFICATE_DIR}/client_key.pem"),
         | 
| 247 243 | 
             
                  tls_ca_certificates: ["#{CERTIFICATE_DIR}/ca_certificate.pem"],
         | 
| 244 | 
            +
                  tls_protocol: :TLSv1_2,
         | 
| 248 245 | 
             
                  verify_peer: false)
         | 
| 249 246 | 
             
                c.start
         | 
| 250 247 | 
             
                c
         | 
| @@ -255,8 +252,4 @@ describe "TLS connection to RabbitMQ with tls_version TLSv1.2 specified", skip: | |
| 255 252 | 
             
              end
         | 
| 256 253 |  | 
| 257 254 | 
             
              include_examples "successful TLS connection"
         | 
| 258 | 
            -
             | 
| 259 | 
            -
              it "connects using TLSv1.2", skip: no_tls12_supported? do
         | 
| 260 | 
            -
                expect(subject.transport.socket.ssl_version).to eq "TLSv1.2"
         | 
| 261 | 
            -
              end
         | 
| 262 255 | 
             
            end
         |