From 59f4bfdd4b610426441a065c282ff11f5c480679 Mon Sep 17 00:00:00 2001 From: Kubernetes Prow Robot Date: Mon, 10 Feb 2020 14:07:54 -0800 Subject: [PATCH] Merge pull request #1073 from fabianvf/fix-py3-hang Cleanup ThreadPool with atexit rather than __del__ (cherry picked from commit 0976d59d6ff206f2f428cabc7a6b7b1144843b2a) --- kubernetes/client/api_client.py | 14 ++++++++++++-- kubernetes/test/test_api_client.py | 25 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 kubernetes/test/test_api_client.py diff --git a/kubernetes/client/api_client.py b/kubernetes/client/api_client.py index 40a451cff5..9e60ded5f5 100644 --- a/kubernetes/client/api_client.py +++ b/kubernetes/client/api_client.py @@ -14,6 +14,7 @@ import os import re import json +import atexit import mimetypes import tempfile from multiprocessing.pool import ThreadPool @@ -74,12 +75,20 @@ def __init__(self, configuration=None, header_name=None, header_value=None, self.cookie = cookie # Set default User-Agent. self.user_agent = 'Swagger-Codegen/10.0.1/python' - - def __del__(self): + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.close() + + def close(self): if self._pool: self._pool.close() self._pool.join() self._pool = None + if hasattr(atexit, 'unregister'): + atexit.unregister(self.close) @property def pool(self): @@ -87,6 +96,7 @@ def pool(self): avoids instantiating unused threadpool for blocking clients. """ if self._pool is None: + atexit.register(self.close) self._pool = ThreadPool(self.pool_threads) return self._pool diff --git a/kubernetes/test/test_api_client.py b/kubernetes/test/test_api_client.py new file mode 100644 index 0000000000..f0a9416cf7 --- /dev/null +++ b/kubernetes/test/test_api_client.py @@ -0,0 +1,25 @@ +# coding: utf-8 + + +import atexit +import weakref +import unittest + +import kubernetes + + +class TestApiClient(unittest.TestCase): + + def test_context_manager_closes_threadpool(self): + with kubernetes.client.ApiClient() as client: + self.assertIsNotNone(client.pool) + pool_ref = weakref.ref(client._pool) + self.assertIsNotNone(pool_ref()) + self.assertIsNone(pool_ref()) + + def test_atexit_closes_threadpool(self): + client = kubernetes.client.ApiClient() + self.assertIsNotNone(client.pool) + self.assertIsNotNone(client._pool) + atexit._run_exitfuncs() + self.assertIsNone(client._pool)