2121
2222class ConnectWaitStrategy (WaitStrategy ):
2323 """
24- Wait strategy that retries a container's _connect method until it succeeds or times out.
24+ Wait strategy that tests database connectivity until it succeeds or times out.
2525
26- This strategy assumes the container has a _connect method and will call it repeatedly
27- until it succeeds or the timeout is reached. It handles transient connection errors
28- and provides appropriate retry logic for database connectivity testing.
26+ This strategy performs database connection testing using SQLAlchemy directly,
27+ handling transient connection errors and providing appropriate retry logic
28+ for database connectivity testing.
2929 """
3030
3131 def __init__ (self , transient_exceptions : Optional [tuple ] = None ):
@@ -34,33 +34,51 @@ def __init__(self, transient_exceptions: Optional[tuple] = None):
3434
3535 def wait_until_ready (self , container : WaitStrategyTarget ) -> None :
3636 """
37- Execute the container's _connect method with retry logic until it succeeds or times out.
37+ Test database connectivity with retry logic until it succeeds or times out.
3838
3939 Args:
40- container: The container that must have a _connect method
40+ container: The SQL container that must have get_connection_url method
4141
4242 Raises:
43- TimeoutError: If _connect fails after timeout
44- AttributeError: If container doesn't have _connect method
45- Exception: Any non-transient errors from _connect
43+ TimeoutError: If connection fails after timeout
44+ AttributeError: If container doesn't have get_connection_url method
45+ ImportError: If SQLAlchemy is not installed
46+ Exception: Any non-transient errors from connection attempts
4647 """
4748 import time
4849
49- if not hasattr (container , "_connect" ):
50- raise AttributeError (f"Container { container } must have a _connect method" )
50+ if not hasattr (container , "get_connection_url" ):
51+ raise AttributeError (f"Container { container } must have a get_connection_url method" )
52+
53+ try :
54+ import sqlalchemy
55+ except ImportError as e :
56+ logger .error ("SQLAlchemy is required for database connectivity testing" )
57+ raise ImportError ("SQLAlchemy is required for database containers" ) from e
5158
5259 start_time = time .time ()
5360
5461 while True :
5562 if time .time () - start_time > self ._startup_timeout :
5663 raise TimeoutError (
57- f"Container _connect failed after { self ._startup_timeout } s timeout. "
64+ f"Database connection failed after { self ._startup_timeout } s timeout. "
5865 f"Hint: Check if the container is ready and the database is accessible."
5966 )
6067
6168 try :
62- container ._connect ()
63- return
69+ connection_url = container .get_connection_url ()
70+ engine = sqlalchemy .create_engine (connection_url )
71+
72+ try :
73+ with engine .connect ():
74+ logger .info ("Database connection test successful" )
75+ return
76+ except Exception as e :
77+ logger .debug (f"Database connection attempt failed: { e } " )
78+ raise
79+ finally :
80+ engine .dispose ()
81+
6482 except self .transient_exceptions as e :
6583 logger .debug (f"Connection attempt failed: { e } , retrying in { self ._poll_interval } s..." )
6684 except Exception as e :
@@ -79,35 +97,6 @@ class SqlContainer(DockerContainer):
7997 Database connection readiness is automatically handled by ConnectWaitStrategy.
8098 """
8199
82- def _connect (self ) -> None :
83- """
84- Test database connectivity using SQLAlchemy.
85-
86- This method performs a single connection test without retry logic.
87- Retry logic is handled by the ConnectWaitStrategy.
88-
89- Raises:
90- ImportError: If SQLAlchemy is not installed
91- Exception: If connection fails
92- """
93- try :
94- import sqlalchemy
95- except ImportError as e :
96- logger .error ("SQLAlchemy is required for database connectivity testing" )
97- raise ImportError ("SQLAlchemy is required for database containers" ) from e
98-
99- connection_url = self .get_connection_url ()
100- engine = sqlalchemy .create_engine (connection_url )
101-
102- try :
103- with engine .connect ():
104- logger .info ("Database connection test successful" )
105- except Exception as e :
106- logger .debug (f"Database connection attempt failed: { e } " )
107- raise
108- finally :
109- engine .dispose ()
110-
111100 def _create_connection_url (
112101 self ,
113102 dialect : str ,
0 commit comments