def test_connection_error_with_pika_exception_as_error(self): """Assert callback is called on connection error.""" connection = "test_connection" error_message = "test_err_msg" mock_connection = mock.Mock() self.consumer._connection = mock_connection with mock.patch("fedora_messaging._session._log") as mock_log: self.consumer._on_connection_error( connection, pika_errs.AMQPConnectionError(error_message)) mock_connection.ioloop.call_later.assert_called_once_with( 1, self.consumer.reconnect) self.assertEqual(self.consumer._channel, None) mock_log.error.assert_called_once_with(repr(error_message))
def _adapter_connect(self): """Connect to the RabbitMQ broker""" super(BlockingConnection, self)._adapter_connect() LOGGER.debug('Post initial config, setting to blocking behaviors') self.socket.setblocking(1) self.socket.settimeout(self.params.socket_timeout) self._socket_timeouts = 0 self._on_connected() self._timeouts = dict() self._wait_on_open() if not self.is_open: raise exceptions.AMQPConnectionError(self.SOCKET_TIMEOUT_THRESHOLD) LOGGER.debug('Adapter connected')
def _wait_on_open(self): """When using a high availability cluster (such as HAProxy) we are always able to connect even though there might be no RabbitMQ backend. So loop while trying to open for up to self.SOCKET_TIMEOUT_THRESHOLD """ socket_timeout_retries = 0 while (not self.is_open and socket_timeout_retries < self.SOCKET_TIMEOUT_THRESHOLD): self._flush_outbound() try: self._handle_read() except socket.timeout: socket_timeout_retries += 1 except socket.error, error: raise exceptions.AMQPConnectionError(error)
def test_publish_reconnect_failed(self): # The publisher must try to re-establish a connection on publish, and # close the connection if it can't be established. self.publisher._channel.publish.side_effect = \ pika_errs.ConnectionClosed(200, 'I wanted to') connection_class_mock = mock.Mock() connection_mock = mock.Mock() connection_class_mock.return_value = connection_mock connection_mock.channel.side_effect = pika_errs.AMQPConnectionError() with mock.patch("fedora_messaging._session.pika.BlockingConnection", connection_class_mock): self.assertRaises(ConnectionException, self.publisher.publish, self.message) # Check that the connection was reestablished connection_class_mock.assert_called_with(self.publisher._parameters) self.assertEqual(self.publisher._connection, connection_mock) connection_mock.close.assert_called_once()
def test_publish_disconnected(self): # The publisher must try to re-establish a connection on publish. self.publisher_channel_publish.side_effect = pika_errs.AMQPConnectionError( 200, "I wanted to" ) connection_class_mock = mock.Mock() connection_mock = mock.Mock() channel_mock = mock.Mock() connection_class_mock.return_value = connection_mock connection_mock.channel.return_value = channel_mock with mock.patch( "fedora_messaging._session.pika.BlockingConnection", connection_class_mock ): self.publisher.publish(self.message) # Check that the connection was reestablished connection_class_mock.assert_called_with(self.publisher._parameters) channel_mock.confirm_delivery.assert_called_once() self.assertEqual(self.publisher._connection, connection_mock) self.assertEqual(self.publisher._channel, channel_mock) publish_mock_method = channel_mock.basic_publish publish_mock_method.assert_called_once()
def _adapter_connect(self): """Connect to the RabbitMQ broker :rtype: bool :raises: pika.Exceptions.AMQPConnectionError """ # Remove the default behavior for connection errors self.callbacks.remove(0, self.ON_CONNECTION_ERROR) error = super(BlockingConnection, self)._adapter_connect() if error: raise exceptions.AMQPConnectionError(error) self.socket.settimeout(self.SOCKET_CONNECT_TIMEOUT) self._frames_written_without_read = 0 self._socket_timeouts = 0 self._timeouts = dict() self._read_poller = ReadPoller(self.socket.fileno()) self._on_connected() while not self.is_open: self.process_data_events() self.socket.settimeout(self.params.socket_timeout) self._set_connection_state(self.CONNECTION_OPEN)
def connectionFailed(self, connection_unused): d, self.ready = self.ready, None if d: attempts = self.params.connection_attempts exc = exceptions.AMQPConnectionError(attempts) d.errback(exc)
class BaseConnection(connection.Connection): """BaseConnection class that should be extended by connection adapters""" # Use epoll's constants to keep life easy READ = 0x0001 WRITE = 0x0004 ERROR = 0x0008 ERRORS_TO_IGNORE = [errno.EWOULDBLOCK, errno.EAGAIN, errno.EINTR] DO_HANDSHAKE = True WARN_ABOUT_IOLOOP = False def __init__(self, parameters=None, on_open_callback=None, stop_ioloop_on_close=True): """Create a new instance of the Connection object. :param pika.connection.Parameters parameters: Connection parameters :param method on_open_callback: Method to call on connection open :param bool stop_ioloop_on_close: Will stop the ioloop when the connection is fully closed. :raises: RuntimeError """ # Let the developer know we could not import SSL if parameters and parameters.ssl and not ssl: raise RuntimeError("SSL specified but it is not available") self.fd = None self.ioloop = None self.stop_ioloop_on_close = stop_ioloop_on_close self.base_events = self.READ | self.ERROR self.event_state = self.base_events self.socket = None self.write_buffer = None super(BaseConnection, self).__init__(parameters, on_open_callback) def add_timeout(self, deadline, callback_method): """Add the callback_method to the IOLoop timer to fire after deadline seconds. Returns a handle to the timeout :param int deadline: The number of seconds to wait to call callback :param method callback_method: The callback method :rtype: str """ return self.ioloop.add_timeout(deadline, callback_method) def close(self, reply_code=200, reply_text='Normal shutdown'): """Disconnect from RabbitMQ. If there are any open channels, it will attempt to close them prior to fully disconnecting. Channels which have active consumers will attempt to send a Basic.Cancel to RabbitMQ to cleanly stop the delivery of messages prior to closing the channel. :param int reply_code: The code number for the close :param str reply_text: The text reason for the close """ super(BaseConnection, self).close(reply_code, reply_text) self._handle_ioloop_stop() def remove_timeout(self, timeout_id): """Remove the timeout from the IOLoop by the ID returned from add_timeout. :rtype: str """ self.ioloop.remove_timeout(timeout_id) def _adapter_connect(self): """Connect to the RabbitMQ broker""" LOGGER.debug('Connecting the adapter to the remote host') reason = 'Unknown' remaining_attempts = self.params.connection_attempts while remaining_attempts: remaining_attempts -= 1 try: self._create_and_connect_to_socket() return except socket.timeout: reason = 'timeout' except socket.error, err: LOGGER.error('socket error: %s', err[-1]) reason = err[-1] self.socket.close() LOGGER.warning('Could not connect due to "%s," retrying in %i sec', reason, self.params.retry_delay) if remaining_attempts: time.sleep(self.params.retry_delay) LOGGER.error('Could not connect: %s', reason) raise exceptions.AMQPConnectionError(self.params.connection_attempts * self.params.retry_delay)
def test_amqp_connection_error_two_params_repr(self): self.assertEqual(repr(exceptions.AMQPConnectionError(1, 'Test')), 'AMQPConnectionError: (1) Test')
def test_amqp_connection_error_one_param_repr(self): self.assertEqual(repr(exceptions.AMQPConnectionError(10)), 'AMQPConnectionError: (10,)')
def test_amqp_connection_error_one_param_repr(self): self.assertEqual( repr(exceptions.AMQPConnectionError(10)), "No connection could be opened after 10 connection attempts")
def on_open_error(conn, err): create_connection_future.set_exception( pika_exceptions.AMQPConnectionError(err))
def _on_connection_failed(self, _connection, _error_message=None): d, self.ready = self.ready, None if d: attempts = self._impl.params.connection_attempts exc = exceptions.AMQPConnectionError(attempts) d.errback(exc)
def connection_failed(self, connection_unused, error_message=None): d, self.ready = self.ready, None if d: attempts = self.params.connection_attempts exc = exceptions.AMQPConnectionError(attempts) d.set_exception(exc)
def on_open_connection_error(self, unused_connection, error_message=None): err('[XMQP] on_open_connection_error %s' % repr(pika_exceptions.AMQPConnectionError(error_message or self._connection.params.connection_attempts))) self._connection.ioloop.stop()
self._socket_connect() return except socket.timeout, timeout: reason = "timeout" except socket.error, err: reason = err[-1] self.socket.close() retry = '' if remaining_attempts: retry = "Retrying in %i seconds with %i retry(s) left" %\ (self.params.retry_delay, remaining_attempts) LOGGER.warning("Could not connect: %s. %s", reason, retry) if remaining_attempts: time.sleep(self.params.retry_delay) LOGGER.error("Could not connect: %s", reason) raise exceptions.AMQPConnectionError(reason) def _adapter_disconnect(self): """Invoked if the connection is being told to disconnect""" self.socket.shutdown(socket.SHUT_RDWR) self._check_state_on_disconnect() self._handle_ioloop_stop() def _check_state_on_disconnect(self): """ Checks to see if we were in opening a connection with RabbitMQ when we were disconnected and raises exceptions for the anticipated exception types. """ if self.connection_state == self.CONNECTION_PROTOCOL: LOGGER.error("Incompatible Protocol Versions")