Merge "Move ConnectionPool and ConnectionContext outside amqp.py"
This commit is contained in:
commit
f4f40ea9a5
|
@ -31,7 +31,6 @@ from oslo_config import cfg
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from oslo_messaging._drivers import common as rpc_common
|
from oslo_messaging._drivers import common as rpc_common
|
||||||
from oslo_messaging._drivers import pool
|
|
||||||
|
|
||||||
deprecated_durable_opts = [
|
deprecated_durable_opts = [
|
||||||
cfg.DeprecatedOpt('amqp_durable_queues',
|
cfg.DeprecatedOpt('amqp_durable_queues',
|
||||||
|
@ -66,122 +65,6 @@ amqp_opts = [
|
||||||
UNIQUE_ID = '_unique_id'
|
UNIQUE_ID = '_unique_id'
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
# NOTE(sileht): Even if rabbit has only one Connection class,
|
|
||||||
# this connection can be used for two purposes:
|
|
||||||
# * wait and receive amqp messages (only do read stuffs on the socket)
|
|
||||||
# * send messages to the broker (only do write stuffs on the socket)
|
|
||||||
# The code inside a connection class is not concurrency safe.
|
|
||||||
# Using one Connection class instance for doing both, will result
|
|
||||||
# of eventlet complaining of multiple greenthreads that read/write the
|
|
||||||
# same fd concurrently... because 'send' and 'listen' run in different
|
|
||||||
# greenthread.
|
|
||||||
# So, a connection cannot be shared between thread/greenthread and
|
|
||||||
# this two variables permit to define the purpose of the connection
|
|
||||||
# to allow drivers to add special handling if needed (like heatbeat).
|
|
||||||
# amqp drivers create 3 kind of connections:
|
|
||||||
# * driver.listen*(): each call create a new 'PURPOSE_LISTEN' connection
|
|
||||||
# * driver.send*(): a pool of 'PURPOSE_SEND' connections is used
|
|
||||||
# * driver internally have another 'PURPOSE_LISTEN' connection dedicated
|
|
||||||
# to wait replies of rpc call
|
|
||||||
PURPOSE_LISTEN = 'listen'
|
|
||||||
PURPOSE_SEND = 'send'
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectionPool(pool.Pool):
|
|
||||||
"""Class that implements a Pool of Connections."""
|
|
||||||
def __init__(self, conf, rpc_conn_pool_size, url, connection_cls):
|
|
||||||
self.connection_cls = connection_cls
|
|
||||||
self.conf = conf
|
|
||||||
self.url = url
|
|
||||||
super(ConnectionPool, self).__init__(rpc_conn_pool_size)
|
|
||||||
self.reply_proxy = None
|
|
||||||
|
|
||||||
# TODO(comstud): Timeout connections not used in a while
|
|
||||||
def create(self, purpose=None):
|
|
||||||
if purpose is None:
|
|
||||||
purpose = PURPOSE_SEND
|
|
||||||
LOG.debug('Pool creating new connection')
|
|
||||||
return self.connection_cls(self.conf, self.url, purpose)
|
|
||||||
|
|
||||||
def empty(self):
|
|
||||||
for item in self.iter_free():
|
|
||||||
item.close()
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectionContext(rpc_common.Connection):
|
|
||||||
"""The class that is actually returned to the create_connection() caller.
|
|
||||||
|
|
||||||
This is essentially a wrapper around Connection that supports 'with'.
|
|
||||||
It can also return a new Connection, or one from a pool.
|
|
||||||
|
|
||||||
The function will also catch when an instance of this class is to be
|
|
||||||
deleted. With that we can return Connections to the pool on exceptions
|
|
||||||
and so forth without making the caller be responsible for catching them.
|
|
||||||
If possible the function makes sure to return a connection to the pool.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, connection_pool, purpose):
|
|
||||||
"""Create a new connection, or get one from the pool."""
|
|
||||||
self.connection = None
|
|
||||||
self.connection_pool = connection_pool
|
|
||||||
pooled = purpose == PURPOSE_SEND
|
|
||||||
if pooled:
|
|
||||||
self.connection = connection_pool.get()
|
|
||||||
else:
|
|
||||||
# a non-pooled connection is requested, so create a new connection
|
|
||||||
self.connection = connection_pool.create(purpose)
|
|
||||||
self.pooled = pooled
|
|
||||||
self.connection.pooled = pooled
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
"""When with ConnectionContext() is used, return self."""
|
|
||||||
return self
|
|
||||||
|
|
||||||
def _done(self):
|
|
||||||
"""If the connection came from a pool, clean it up and put it back.
|
|
||||||
If it did not come from a pool, close it.
|
|
||||||
"""
|
|
||||||
if self.connection:
|
|
||||||
if self.pooled:
|
|
||||||
# Reset the connection so it's ready for the next caller
|
|
||||||
# to grab from the pool
|
|
||||||
try:
|
|
||||||
self.connection.reset()
|
|
||||||
except Exception:
|
|
||||||
LOG.exception("Fail to reset the connection, drop it")
|
|
||||||
try:
|
|
||||||
self.connection.close()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
self.connection = self.connection_pool.create()
|
|
||||||
finally:
|
|
||||||
self.connection_pool.put(self.connection)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
self.connection.close()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
self.connection = None
|
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, tb):
|
|
||||||
"""End of 'with' statement. We're done here."""
|
|
||||||
self._done()
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
"""Caller is done with this connection. Make sure we cleaned up."""
|
|
||||||
self._done()
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
"""Caller is done with this connection."""
|
|
||||||
self._done()
|
|
||||||
|
|
||||||
def __getattr__(self, key):
|
|
||||||
"""Proxy all other calls to the Connection instance."""
|
|
||||||
if self.connection:
|
|
||||||
return getattr(self.connection, key)
|
|
||||||
else:
|
|
||||||
raise rpc_common.InvalidRPCConnectionReuse()
|
|
||||||
|
|
||||||
|
|
||||||
class RpcContext(rpc_common.CommonRpcContext):
|
class RpcContext(rpc_common.CommonRpcContext):
|
||||||
"""Context that supports replying to a rpc.call."""
|
"""Context that supports replying to a rpc.call."""
|
||||||
|
|
|
@ -100,7 +100,7 @@ class AMQPIncomingMessage(base.IncomingMessage):
|
||||||
return
|
return
|
||||||
|
|
||||||
with self.listener.driver._get_connection(
|
with self.listener.driver._get_connection(
|
||||||
rpc_amqp.PURPOSE_SEND) as conn:
|
rpc_common.PURPOSE_SEND) as conn:
|
||||||
if self.listener.driver.send_single_reply:
|
if self.listener.driver.send_single_reply:
|
||||||
self._send_reply(conn, reply, failure, log_failure=log_failure,
|
self._send_reply(conn, reply, failure, log_failure=log_failure,
|
||||||
ending=True)
|
ending=True)
|
||||||
|
@ -366,9 +366,9 @@ class AMQPDriverBase(base.BaseDriver):
|
||||||
def _get_exchange(self, target):
|
def _get_exchange(self, target):
|
||||||
return target.exchange or self._default_exchange
|
return target.exchange or self._default_exchange
|
||||||
|
|
||||||
def _get_connection(self, purpose=rpc_amqp.PURPOSE_SEND):
|
def _get_connection(self, purpose=rpc_common.PURPOSE_SEND):
|
||||||
return rpc_amqp.ConnectionContext(self._connection_pool,
|
return rpc_common.ConnectionContext(self._connection_pool,
|
||||||
purpose=purpose)
|
purpose=purpose)
|
||||||
|
|
||||||
def _get_reply_q(self):
|
def _get_reply_q(self):
|
||||||
with self._reply_q_lock:
|
with self._reply_q_lock:
|
||||||
|
@ -377,7 +377,7 @@ class AMQPDriverBase(base.BaseDriver):
|
||||||
|
|
||||||
reply_q = 'reply_' + uuid.uuid4().hex
|
reply_q = 'reply_' + uuid.uuid4().hex
|
||||||
|
|
||||||
conn = self._get_connection(rpc_amqp.PURPOSE_LISTEN)
|
conn = self._get_connection(rpc_common.PURPOSE_LISTEN)
|
||||||
|
|
||||||
self._waiter = ReplyWaiter(reply_q, conn,
|
self._waiter = ReplyWaiter(reply_q, conn,
|
||||||
self._allowed_remote_exmods)
|
self._allowed_remote_exmods)
|
||||||
|
@ -422,7 +422,7 @@ class AMQPDriverBase(base.BaseDriver):
|
||||||
log_msg = "CAST unique_id: %s " % unique_id
|
log_msg = "CAST unique_id: %s " % unique_id
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with self._get_connection(rpc_amqp.PURPOSE_SEND) as conn:
|
with self._get_connection(rpc_common.PURPOSE_SEND) as conn:
|
||||||
if notify:
|
if notify:
|
||||||
exchange = self._get_exchange(target)
|
exchange = self._get_exchange(target)
|
||||||
log_msg += "NOTIFY exchange '%(exchange)s'" \
|
log_msg += "NOTIFY exchange '%(exchange)s'" \
|
||||||
|
@ -468,7 +468,7 @@ class AMQPDriverBase(base.BaseDriver):
|
||||||
envelope=(version == 2.0), notify=True, retry=retry)
|
envelope=(version == 2.0), notify=True, retry=retry)
|
||||||
|
|
||||||
def listen(self, target):
|
def listen(self, target):
|
||||||
conn = self._get_connection(rpc_amqp.PURPOSE_LISTEN)
|
conn = self._get_connection(rpc_common.PURPOSE_LISTEN)
|
||||||
|
|
||||||
listener = AMQPListener(self, conn)
|
listener = AMQPListener(self, conn)
|
||||||
|
|
||||||
|
@ -484,7 +484,7 @@ class AMQPDriverBase(base.BaseDriver):
|
||||||
return listener
|
return listener
|
||||||
|
|
||||||
def listen_for_notifications(self, targets_and_priorities, pool):
|
def listen_for_notifications(self, targets_and_priorities, pool):
|
||||||
conn = self._get_connection(rpc_amqp.PURPOSE_LISTEN)
|
conn = self._get_connection(rpc_common.PURPOSE_LISTEN)
|
||||||
|
|
||||||
listener = AMQPListener(self, conn)
|
listener = AMQPListener(self, conn)
|
||||||
for target, priority in targets_and_priorities:
|
for target, priority in targets_and_priorities:
|
||||||
|
|
|
@ -348,3 +348,99 @@ class DecayingTimer(object):
|
||||||
if left <= 0 and timeout_callback is not None:
|
if left <= 0 and timeout_callback is not None:
|
||||||
timeout_callback(*args, **kwargs)
|
timeout_callback(*args, **kwargs)
|
||||||
return left if maximum is None else min(left, maximum)
|
return left if maximum is None else min(left, maximum)
|
||||||
|
|
||||||
|
|
||||||
|
# NOTE(sileht): Even if rabbit has only one Connection class,
|
||||||
|
# this connection can be used for two purposes:
|
||||||
|
# * wait and receive amqp messages (only do read stuffs on the socket)
|
||||||
|
# * send messages to the broker (only do write stuffs on the socket)
|
||||||
|
# The code inside a connection class is not concurrency safe.
|
||||||
|
# Using one Connection class instance for doing both, will result
|
||||||
|
# of eventlet complaining of multiple greenthreads that read/write the
|
||||||
|
# same fd concurrently... because 'send' and 'listen' run in different
|
||||||
|
# greenthread.
|
||||||
|
# So, a connection cannot be shared between thread/greenthread and
|
||||||
|
# this two variables permit to define the purpose of the connection
|
||||||
|
# to allow drivers to add special handling if needed (like heatbeat).
|
||||||
|
# amqp drivers create 3 kind of connections:
|
||||||
|
# * driver.listen*(): each call create a new 'PURPOSE_LISTEN' connection
|
||||||
|
# * driver.send*(): a pool of 'PURPOSE_SEND' connections is used
|
||||||
|
# * driver internally have another 'PURPOSE_LISTEN' connection dedicated
|
||||||
|
# to wait replies of rpc call
|
||||||
|
PURPOSE_LISTEN = 'listen'
|
||||||
|
PURPOSE_SEND = 'send'
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionContext(Connection):
|
||||||
|
"""The class that is actually returned to the create_connection() caller.
|
||||||
|
|
||||||
|
This is essentially a wrapper around Connection that supports 'with'.
|
||||||
|
It can also return a new Connection, or one from a pool.
|
||||||
|
|
||||||
|
The function will also catch when an instance of this class is to be
|
||||||
|
deleted. With that we can return Connections to the pool on exceptions
|
||||||
|
and so forth without making the caller be responsible for catching them.
|
||||||
|
If possible the function makes sure to return a connection to the pool.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, connection_pool, purpose):
|
||||||
|
"""Create a new connection, or get one from the pool."""
|
||||||
|
self.connection = None
|
||||||
|
self.connection_pool = connection_pool
|
||||||
|
pooled = purpose == PURPOSE_SEND
|
||||||
|
if pooled:
|
||||||
|
self.connection = connection_pool.get()
|
||||||
|
else:
|
||||||
|
# a non-pooled connection is requested, so create a new connection
|
||||||
|
self.connection = connection_pool.create(purpose)
|
||||||
|
self.pooled = pooled
|
||||||
|
self.connection.pooled = pooled
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
"""When with ConnectionContext() is used, return self."""
|
||||||
|
return self
|
||||||
|
|
||||||
|
def _done(self):
|
||||||
|
"""If the connection came from a pool, clean it up and put it back.
|
||||||
|
If it did not come from a pool, close it.
|
||||||
|
"""
|
||||||
|
if self.connection:
|
||||||
|
if self.pooled:
|
||||||
|
# Reset the connection so it's ready for the next caller
|
||||||
|
# to grab from the pool
|
||||||
|
try:
|
||||||
|
self.connection.reset()
|
||||||
|
except Exception:
|
||||||
|
LOG.exception("Fail to reset the connection, drop it")
|
||||||
|
try:
|
||||||
|
self.connection.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
self.connection = self.connection_pool.create()
|
||||||
|
finally:
|
||||||
|
self.connection_pool.put(self.connection)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
self.connection.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
self.connection = None
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, tb):
|
||||||
|
"""End of 'with' statement. We're done here."""
|
||||||
|
self._done()
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
"""Caller is done with this connection. Make sure we cleaned up."""
|
||||||
|
self._done()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
"""Caller is done with this connection."""
|
||||||
|
self._done()
|
||||||
|
|
||||||
|
def __getattr__(self, key):
|
||||||
|
"""Proxy all other calls to the Connection instance."""
|
||||||
|
if self.connection:
|
||||||
|
return getattr(self.connection, key)
|
||||||
|
else:
|
||||||
|
raise InvalidRPCConnectionReuse()
|
||||||
|
|
|
@ -37,6 +37,7 @@ from oslo_messaging._drivers import amqp as rpc_amqp
|
||||||
from oslo_messaging._drivers import amqpdriver
|
from oslo_messaging._drivers import amqpdriver
|
||||||
from oslo_messaging._drivers import base
|
from oslo_messaging._drivers import base
|
||||||
from oslo_messaging._drivers import common as rpc_common
|
from oslo_messaging._drivers import common as rpc_common
|
||||||
|
from oslo_messaging._drivers import pool
|
||||||
from oslo_messaging._i18n import _
|
from oslo_messaging._i18n import _
|
||||||
from oslo_messaging._i18n import _LE
|
from oslo_messaging._i18n import _LE
|
||||||
from oslo_messaging._i18n import _LI
|
from oslo_messaging._i18n import _LI
|
||||||
|
@ -456,7 +457,7 @@ class Connection(object):
|
||||||
# NOTE(sileht): if purpose is PURPOSE_LISTEN
|
# NOTE(sileht): if purpose is PURPOSE_LISTEN
|
||||||
# we don't need the lock because we don't
|
# we don't need the lock because we don't
|
||||||
# have a heartbeat thread
|
# have a heartbeat thread
|
||||||
if purpose == rpc_amqp.PURPOSE_SEND:
|
if purpose == rpc_common.PURPOSE_SEND:
|
||||||
self._connection_lock = ConnectionLock()
|
self._connection_lock = ConnectionLock()
|
||||||
else:
|
else:
|
||||||
self._connection_lock = DummyConnectionLock()
|
self._connection_lock = DummyConnectionLock()
|
||||||
|
@ -496,7 +497,7 @@ class Connection(object):
|
||||||
# the consume code does the heartbeat stuff
|
# the consume code does the heartbeat stuff
|
||||||
# we don't need a thread
|
# we don't need a thread
|
||||||
self._heartbeat_thread = None
|
self._heartbeat_thread = None
|
||||||
if purpose == rpc_amqp.PURPOSE_SEND:
|
if purpose == rpc_common.PURPOSE_SEND:
|
||||||
self._heartbeat_start()
|
self._heartbeat_start()
|
||||||
|
|
||||||
LOG.debug('Connected to AMQP server on %(hostname)s:%(port)s '
|
LOG.debug('Connected to AMQP server on %(hostname)s:%(port)s '
|
||||||
|
@ -1159,7 +1160,7 @@ class RabbitDriver(amqpdriver.AMQPDriverBase):
|
||||||
conf.register_opts(rpc_amqp.amqp_opts, group=opt_group)
|
conf.register_opts(rpc_amqp.amqp_opts, group=opt_group)
|
||||||
conf.register_opts(base.base_opts, group=opt_group)
|
conf.register_opts(base.base_opts, group=opt_group)
|
||||||
|
|
||||||
connection_pool = rpc_amqp.ConnectionPool(
|
connection_pool = pool.ConnectionPool(
|
||||||
conf, conf.oslo_messaging_rabbit.rpc_conn_pool_size,
|
conf, conf.oslo_messaging_rabbit.rpc_conn_pool_size,
|
||||||
url, Connection)
|
url, Connection)
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,13 @@ import abc
|
||||||
import collections
|
import collections
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from oslo_messaging._drivers import common
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
class Pool(object):
|
class Pool(object):
|
||||||
|
@ -86,3 +91,24 @@ class Pool(object):
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def create(self):
|
def create(self):
|
||||||
"""Construct a new item."""
|
"""Construct a new item."""
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionPool(Pool):
|
||||||
|
"""Class that implements a Pool of Connections."""
|
||||||
|
def __init__(self, conf, rpc_conn_pool_size, url, connection_cls):
|
||||||
|
self.connection_cls = connection_cls
|
||||||
|
self.conf = conf
|
||||||
|
self.url = url
|
||||||
|
super(ConnectionPool, self).__init__(rpc_conn_pool_size)
|
||||||
|
self.reply_proxy = None
|
||||||
|
|
||||||
|
# TODO(comstud): Timeout connections not used in a while
|
||||||
|
def create(self, purpose=None):
|
||||||
|
if purpose is None:
|
||||||
|
purpose = common.PURPOSE_SEND
|
||||||
|
LOG.debug('Pool creating new connection')
|
||||||
|
return self.connection_cls(self.conf, self.url, purpose)
|
||||||
|
|
||||||
|
def empty(self):
|
||||||
|
for item in self.iter_free():
|
||||||
|
item.close()
|
||||||
|
|
|
@ -177,7 +177,7 @@ class TestRabbitPublisher(test_utils.BaseTestCase):
|
||||||
def test_send_with_timeout(self, fake_publish):
|
def test_send_with_timeout(self, fake_publish):
|
||||||
transport = oslo_messaging.get_transport(self.conf,
|
transport = oslo_messaging.get_transport(self.conf,
|
||||||
'kombu+memory:////')
|
'kombu+memory:////')
|
||||||
with transport._driver._get_connection(amqp.PURPOSE_SEND) as pool_conn:
|
with transport._driver._get_connection(driver_common.PURPOSE_SEND) as pool_conn:
|
||||||
conn = pool_conn.connection
|
conn = pool_conn.connection
|
||||||
conn._publish(mock.Mock(), 'msg', routing_key='routing_key',
|
conn._publish(mock.Mock(), 'msg', routing_key='routing_key',
|
||||||
timeout=1)
|
timeout=1)
|
||||||
|
@ -187,7 +187,7 @@ class TestRabbitPublisher(test_utils.BaseTestCase):
|
||||||
def test_send_no_timeout(self, fake_publish):
|
def test_send_no_timeout(self, fake_publish):
|
||||||
transport = oslo_messaging.get_transport(self.conf,
|
transport = oslo_messaging.get_transport(self.conf,
|
||||||
'kombu+memory:////')
|
'kombu+memory:////')
|
||||||
with transport._driver._get_connection(amqp.PURPOSE_SEND) as pool_conn:
|
with transport._driver._get_connection(driver_common.PURPOSE_SEND) as pool_conn:
|
||||||
conn = pool_conn.connection
|
conn = pool_conn.connection
|
||||||
conn._publish(mock.Mock(), 'msg', routing_key='routing_key')
|
conn._publish(mock.Mock(), 'msg', routing_key='routing_key')
|
||||||
fake_publish.assert_called_with('msg', expiration=None)
|
fake_publish.assert_called_with('msg', expiration=None)
|
||||||
|
@ -207,7 +207,7 @@ class TestRabbitPublisher(test_utils.BaseTestCase):
|
||||||
type='topic',
|
type='topic',
|
||||||
passive=False)
|
passive=False)
|
||||||
|
|
||||||
with transport._driver._get_connection(amqp.PURPOSE_SEND) as pool_conn:
|
with transport._driver._get_connection(driver_common.PURPOSE_SEND) as pool_conn:
|
||||||
conn = pool_conn.connection
|
conn = pool_conn.connection
|
||||||
exc = conn.connection.channel_errors[0]
|
exc = conn.connection.channel_errors[0]
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ class TestRabbitConsume(test_utils.BaseTestCase):
|
||||||
'kombu+memory:////')
|
'kombu+memory:////')
|
||||||
self.addCleanup(transport.cleanup)
|
self.addCleanup(transport.cleanup)
|
||||||
deadline = time.time() + 6
|
deadline = time.time() + 6
|
||||||
with transport._driver._get_connection(amqp.PURPOSE_LISTEN) as conn:
|
with transport._driver._get_connection(driver_common.PURPOSE_LISTEN) as conn:
|
||||||
self.assertRaises(driver_common.Timeout,
|
self.assertRaises(driver_common.Timeout,
|
||||||
conn.consume, timeout=3)
|
conn.consume, timeout=3)
|
||||||
|
|
||||||
|
@ -259,7 +259,7 @@ class TestRabbitConsume(test_utils.BaseTestCase):
|
||||||
transport = oslo_messaging.get_transport(self.conf,
|
transport = oslo_messaging.get_transport(self.conf,
|
||||||
'kombu+memory:////')
|
'kombu+memory:////')
|
||||||
self.addCleanup(transport.cleanup)
|
self.addCleanup(transport.cleanup)
|
||||||
with transport._driver._get_connection(amqp.PURPOSE_LISTEN) as conn:
|
with transport._driver._get_connection(driver_common.PURPOSE_LISTEN) as conn:
|
||||||
channel = conn.connection.channel
|
channel = conn.connection.channel
|
||||||
with mock.patch('kombu.connection.Connection.connected',
|
with mock.patch('kombu.connection.Connection.connected',
|
||||||
new_callable=mock.PropertyMock,
|
new_callable=mock.PropertyMock,
|
||||||
|
@ -902,7 +902,7 @@ class RpcKombuHATestCase(test_utils.BaseTestCase):
|
||||||
# starting from the first broker in the list
|
# starting from the first broker in the list
|
||||||
url = oslo_messaging.TransportURL.parse(self.conf, None)
|
url = oslo_messaging.TransportURL.parse(self.conf, None)
|
||||||
self.connection = rabbit_driver.Connection(self.conf, url,
|
self.connection = rabbit_driver.Connection(self.conf, url,
|
||||||
amqp.PURPOSE_SEND)
|
driver_common.PURPOSE_SEND)
|
||||||
self.addCleanup(self.connection.close)
|
self.addCleanup(self.connection.close)
|
||||||
|
|
||||||
def test_ensure_four_retry(self):
|
def test_ensure_four_retry(self):
|
||||||
|
|
Loading…
Reference in New Issue