Skip to content

Commit 29e4ece

Browse files
committed
Better Strategy
1 parent 0f53ccb commit 29e4ece

File tree

1 file changed

+24
-18
lines changed
  • modules/generic/testcontainers/generic

1 file changed

+24
-18
lines changed

modules/generic/testcontainers/generic/sql.py

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,46 +19,52 @@
1919
SQL_TRANSIENT_EXCEPTIONS = (TimeoutError, ConnectionError, *ADDITIONAL_TRANSIENT_ERRORS)
2020

2121

22-
class ExceptionsWaitStrategy(WaitStrategy):
22+
class ConnectWaitStrategy(WaitStrategy):
2323
"""
24-
Generic wait strategy that retries a callable until it succeeds or times out.
24+
Wait strategy that retries a container's _connect method until it succeeds or times out.
2525
26-
This strategy can be used with any container method that needs retry logic
27-
for handling transient errors. It calls the provided callable repeatedly
28-
until it succeeds or the timeout is reached.
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.
2929
"""
3030

31-
def __init__(self, callable_func: callable, transient_exceptions: Optional[tuple] = None):
31+
def __init__(self, transient_exceptions: Optional[tuple] = None):
3232
super().__init__()
33-
self.callable_func = callable_func
3433
self.transient_exceptions = transient_exceptions or (TimeoutError, ConnectionError)
3534

3635
def wait_until_ready(self, container: WaitStrategyTarget) -> None:
3736
"""
38-
Execute the callable with retry logic until it succeeds or times out.
37+
Execute the container's _connect method with retry logic until it succeeds or times out.
38+
39+
Args:
40+
container: The container that must have a _connect method
3941
4042
Raises:
41-
TimeoutError: If callable fails after timeout
42-
Exception: Any non-transient errors from the callable
43+
TimeoutError: If _connect fails after timeout
44+
AttributeError: If container doesn't have _connect method
45+
Exception: Any non-transient errors from _connect
4346
"""
4447
import time
4548

49+
if not hasattr(container, "_connect"):
50+
raise AttributeError(f"Container {container} must have a _connect method")
51+
4652
start_time = time.time()
4753

4854
while True:
4955
if time.time() - start_time > self._startup_timeout:
5056
raise TimeoutError(
51-
f"Callable failed after {self._startup_timeout}s timeout. "
52-
f"Hint: Check if the container is ready and the operation can succeed."
57+
f"Container _connect failed after {self._startup_timeout}s timeout. "
58+
f"Hint: Check if the container is ready and the database is accessible."
5359
)
5460

5561
try:
56-
self.callable_func()
62+
container._connect()
5763
return
5864
except self.transient_exceptions as e:
59-
logger.debug(f"Callable attempt failed: {e}, retrying in {self._poll_interval}s...")
65+
logger.debug(f"Connection attempt failed: {e}, retrying in {self._poll_interval}s...")
6066
except Exception as e:
61-
logger.error(f"Callable failed with non-transient error: {e}")
67+
logger.error(f"Connection failed with non-transient error: {e}")
6268
raise
6369

6470
time.sleep(self._poll_interval)
@@ -70,15 +76,15 @@ class SqlContainer(DockerContainer):
7076
7177
This class can serve as a base for database-specific container implementations.
7278
It provides connection management, URL construction, and basic lifecycle methods.
73-
Database connection readiness is automatically handled by ExceptionsWaitStrategy.
79+
Database connection readiness is automatically handled by ConnectWaitStrategy.
7480
"""
7581

7682
def _connect(self) -> None:
7783
"""
7884
Test database connectivity using SQLAlchemy.
7985
8086
This method performs a single connection test without retry logic.
81-
Retry logic is handled by the DatabaseConnectionWaitStrategy.
87+
Retry logic is handled by the ConnectWaitStrategy.
8288
8389
Raises:
8490
ImportError: If SQLAlchemy is not installed
@@ -184,7 +190,7 @@ def start(self) -> "SqlContainer":
184190

185191
try:
186192
self._configure()
187-
self.waiting_for(ExceptionsWaitStrategy(self._connect, SQL_TRANSIENT_EXCEPTIONS))
193+
self.waiting_for(ConnectWaitStrategy(SQL_TRANSIENT_EXCEPTIONS))
188194
super().start()
189195
self._transfer_seed()
190196
logger.info("Database container started successfully")

0 commit comments

Comments
 (0)