Skip to content

Commit a348659

Browse files
fix: remove ConnectorLoopError from connector.connect (#1170)
Python packages like gevent have monkey patching abilities and use greenlet processes to replace synchronous code in an "asynchronous" fashion. The ConnectorLoopError in connector.connect was put in as a safe-guard to try and prevent improper async driver usage where users would accidentally call connector.connect for asyncpg instead of calling connector.connect_async, leading to an indefinite hang. However, this error is preventing support for gevent which schedules tasks in its greenlet threads.
1 parent 76af210 commit a348659

File tree

2 files changed

+7
-35
lines changed

2 files changed

+7
-35
lines changed

google/cloud/sql/connector/connector.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
from google.cloud.sql.connector.enums import DriverMapping
3333
from google.cloud.sql.connector.enums import IPTypes
3434
from google.cloud.sql.connector.enums import RefreshStrategy
35-
from google.cloud.sql.connector.exceptions import ConnectorLoopError
3635
from google.cloud.sql.connector.instance import RefreshAheadCache
3736
from google.cloud.sql.connector.lazy import LazyRefreshCache
3837
import google.cloud.sql.connector.pg8000 as pg8000
@@ -208,27 +207,16 @@ def connect(
208207
209208
Returns:
210209
A DB-API connection to the specified Cloud SQL instance.
211-
212-
Raises:
213-
ConnectorLoopError: Event loop for background refresh is running in
214-
current thread. Error instead of hanging indefinitely.
215210
"""
216-
try:
217-
# check if event loop is running in current thread
218-
if self._loop == asyncio.get_running_loop():
219-
raise ConnectorLoopError(
220-
"Connector event loop is running in current thread!"
221-
"Event loop must be attached to a different thread to prevent blocking code!"
222-
)
223-
# asyncio.get_running_loop will throw RunTimeError if no running loop is present
224-
except RuntimeError:
225-
pass
226211

227-
# if event loop is not in current thread, proceed with connection
228-
connect_task = asyncio.run_coroutine_threadsafe(
229-
self.connect_async(instance_connection_string, driver, **kwargs), self._loop
212+
# connect runs sync database connections on background thread.
213+
# Async database connections should call 'connect_async' directly to
214+
# avoid hanging indefinitely.
215+
connect_future = asyncio.run_coroutine_threadsafe(
216+
self.connect_async(instance_connection_string, driver, **kwargs),
217+
self._loop,
230218
)
231-
return connect_task.result()
219+
return connect_future.result()
232220

233221
async def connect_async(
234222
self, instance_connection_string: str, driver: str, **kwargs: Any

tests/unit/test_connector.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
from google.cloud.sql.connector import IPTypes
2828
from google.cloud.sql.connector.client import CloudSQLClient
2929
from google.cloud.sql.connector.exceptions import CloudSQLIPTypeError
30-
from google.cloud.sql.connector.exceptions import ConnectorLoopError
3130
from google.cloud.sql.connector.exceptions import IncompatibleDriverError
3231
from google.cloud.sql.connector.instance import RefreshAheadCache
3332

@@ -88,21 +87,6 @@ def test_connect_with_unsupported_driver(fake_credentials: Credentials) -> None:
8887
assert exc_info.value.args[0] == "Driver 'bad_driver' is not supported."
8988

9089

91-
@pytest.mark.asyncio
92-
async def test_connect_ConnectorLoopError(fake_credentials: Credentials) -> None:
93-
"""Test that ConnectorLoopError is thrown when Connector.connect
94-
is called with event loop running in current thread."""
95-
current_loop = asyncio.get_running_loop()
96-
connector = Connector(credentials=fake_credentials, loop=current_loop)
97-
# try to connect using current thread's loop, should raise error
98-
pytest.raises(
99-
ConnectorLoopError,
100-
connector.connect,
101-
"my-project:my-region:my-instance",
102-
"pg8000",
103-
)
104-
105-
10690
def test_Connector_Init(fake_credentials: Credentials) -> None:
10791
"""Test that Connector __init__ sets default properties properly."""
10892
with patch("google.auth.default") as mock_auth:

0 commit comments

Comments
 (0)