Description: WIP dont-merge: Clean-up memcache connection sockets
 The ConnectionPool currently opens sockets, but never closes them. As a
 result, any client using oslo.cache memcache pool leaves sockets in a
 CLOSE_WAIT state, with the source port not being re-usable.
 .
 In our production system, were we have A LOT of activity, this creates
 a storm of non-reusable ports: all source ports are in use, making the
 node unuseable for other things.
 .
 This patch adds a __del__ destructor closing inactive connections,
 fixing the issue.
Author: Thomas Goirand <zigo@debian.org>
Date: Mon, 06 Nov 2023 10:55:45 +0100
Change-Id: I09d632346c76d1aff7c534f0d040162d1985f548
Forwarded: https://review.opendev.org/c/openstack/oslo.cache/+/900158
Last-Update: 2023-11-14

Index: python-oslo.cache/oslo_cache/_memcache_pool.py
===================================================================
--- python-oslo.cache.orig/oslo_cache/_memcache_pool.py
+++ python-oslo.cache/oslo_cache/_memcache_pool.py
@@ -114,6 +114,27 @@ class ConnectionPool(queue.Queue):
                 self._do_log(
                     LOG.warning, "Unable to cleanup a connection: %s", e)
 
+    def __del__(self):
+        """Delete the connection pool.
+
+        Destory all connections left in the queue.
+        """
+        while True:
+            # As per https://docs.python.org/3/library/collections.html
+            # self.queue.pop() will raise IndexError when no elements are
+            # present, ending the while True: loop.
+            # The logic loops over all connections in the queue but it does
+            # not retry for a single one in case a connection closure fails
+            # then it leaves that one and process the next.
+            try:
+                conn = self.queue.pop().connection
+                self._destroy_connection(conn)
+            except IndexError:
+                break
+            except Exception as e:
+                self._do_log(
+                    LOG.warning, "Unable to cleanup a connection: %s", e)
+
     def _create_connection(self):
         """Returns a connection instance.
 
