diff --git a/google/cloud/alloydb/connector/connector.py b/google/cloud/alloydb/connector/connector.py index 696e5c5c..f7b0822b 100644 --- a/google/cloud/alloydb/connector/connector.py +++ b/google/cloud/alloydb/connector/connector.py @@ -305,15 +305,17 @@ def __exit__( def close(self) -> None: """Close Connector by stopping tasks and releasing resources.""" - close_future = asyncio.run_coroutine_threadsafe( - self.close_async(), loop=self._loop - ) - # Will attempt to gracefully shut down tasks for 3s - close_future.result(timeout=3) + if self._loop.is_running(): + close_future = asyncio.run_coroutine_threadsafe( + self.close_async(), loop=self._loop + ) + # Will attempt to gracefully shut down tasks for 3s + close_future.result(timeout=3) # if background thread exists for Connector, clean it up - if self._thread: - # stop event loop running in background thread - self._loop.call_soon_threadsafe(self._loop.stop) + if self._thread.is_alive(): + if self._loop.is_running(): + # stop event loop running in background thread + self._loop.call_soon_threadsafe(self._loop.stop) # wait for thread to finish closing (i.e. loop to stop) self._thread.join() @@ -325,3 +327,7 @@ async def close_async(self) -> None: ) if self._client: await self._client.close() + + def __del__(self) -> None: + """Close Connector as part of garbage collection""" + self.close() diff --git a/tests/unit/test_connector.py b/tests/unit/test_connector.py index bf8ebe4d..a0761245 100644 --- a/tests/unit/test_connector.py +++ b/tests/unit/test_connector.py @@ -102,3 +102,16 @@ def test_connect_unsupported_driver(credentials: FakeCredentials) -> None: exc_info.value.args[0] == "Driver 'bad_driver' is not a supported database driver." ) + + +def test_Connector_close_called_multiple_times(credentials: FakeCredentials) -> None: + """Test that Connector.close can be called multiple times.""" + # open and close Connector object + connector = Connector(credentials=credentials) + # verify background thread exists + assert connector._thread + connector.close() + # check that connector thread is no longer running + assert connector._thread.is_alive() is False + # call connector.close a second time + connector.close()