ghettoq
ghettoq copied to clipboard
MutliBackend's monkey patching of `drain_events` leads to connection leaks
In the establish_connection
method of MultiBackend
, it monkey patches the connection's drain_events
method:
def establish_connection(self):
conninfo = self.connection
conn = Connection(self.type, host=conninfo.hostname,
user=conninfo.userid,
password=conninfo.password,
database=conninfo.virtual_host,
port=conninfo.port)
conn.drain_events = self.drain_events # << here
return conn
But this leads to problems, because MultiBackend.drain_events
method calls MutiBackend.channel
, which opens up a new connection… But there is no reference to that connection from the connection returned by establish_connection
.
For example:
>>> conn = establish_connection.establish_connection()
>>> conn.drain_events() # creates a new connection
...
>>> conn.close()
This code looks correct, but will in fact leave a dangling connection (ie, the one created during drain_events
).
This is a problem because carrot.connection.BrokerConnection._establish_connection
is:
def _establish_connection(self):
return self.create_backend().establish_connection()
Which means that a backend is being created, but no reference is kept to it. So, for example:
>>> conn = broker._establish_connection().drain_events()
>>> conn.drain_events()
>>> conn.close()
Will leave a dangling connection with no direct references (ie, because the only reference is through conn.drain_events
).