From e1a7fecdca745c25ba99f3498803978d83ce8c3d Mon Sep 17 00:00:00 2001 From: Jason <31104990+ING-XIAOJIAN@users.noreply.github.com> Date: Thu, 11 Jan 2024 18:33:07 +0800 Subject: [PATCH] Fix possible pipeline connections leak (#3104) * Update cluster.py When Executing "n.write()" may generate some unknown errors(e.g. DataError), which could result in the connection not being released. * Update cluster.py * Update cluster.py release connection move to "try...finally" * Update cluster.py fix the linters * fix problems of code review --- redis/cluster.py | 54 +++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/redis/cluster.py b/redis/cluster.py index 7bdf4c1951..e558be1689 100644 --- a/redis/cluster.py +++ b/redis/cluster.py @@ -2166,32 +2166,34 @@ def _send_cluster_commands( # we dont' multiplex on the sockets as they come available, # but that shouldn't make too much difference. node_commands = nodes.values() - for n in node_commands: - n.write() - - for n in node_commands: - n.read() - - # release all of the redis connections we allocated earlier - # back into the connection pool. - # we used to do this step as part of a try/finally block, - # but it is really dangerous to - # release connections back into the pool if for some - # reason the socket has data still left in it - # from a previous operation. The write and - # read operations already have try/catch around them for - # all known types of errors including connection - # and socket level errors. - # So if we hit an exception, something really bad - # happened and putting any oF - # these connections back into the pool is a very bad idea. - # the socket might have unread buffer still sitting in it, - # and then the next time we read from it we pass the - # buffered result back from a previous command and - # every single request after to that connection will always get - # a mismatched result. - for n in nodes.values(): - n.connection_pool.release(n.connection) + try: + node_commands = nodes.values() + for n in node_commands: + n.write() + + for n in node_commands: + n.read() + finally: + # release all of the redis connections we allocated earlier + # back into the connection pool. + # we used to do this step as part of a try/finally block, + # but it is really dangerous to + # release connections back into the pool if for some + # reason the socket has data still left in it + # from a previous operation. The write and + # read operations already have try/catch around them for + # all known types of errors including connection + # and socket level errors. + # So if we hit an exception, something really bad + # happened and putting any oF + # these connections back into the pool is a very bad idea. + # the socket might have unread buffer still sitting in it, + # and then the next time we read from it we pass the + # buffered result back from a previous command and + # every single request after to that connection will always get + # a mismatched result. + for n in nodes.values(): + n.connection_pool.release(n.connection) # if the response isn't an exception it is a # valid response from the node