testcontainers-java icon indicating copy to clipboard operation
testcontainers-java copied to clipboard

[Enhancement]: JdbcDatabaseContainer - Improve ``waitUntilContainerStarted``

Open AB-xdev opened this issue 5 months ago • 1 comments

Module

Core

Proposal

Currently https://github.com/testcontainers/testcontainers-java/blob/7d8301903a6b45591605fd376702d24fc878a61d/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java#L176-L216 behaves very weird and this also impacts performance:

  • It doesn't utilize WaitStrategy and completely ignores/overrides it
  • It constantly tries to query if the container is running or builds database connections (these are very costly in terms of CPU usage)
    • These attempts use a hardcoded throttling value of 100ms and completely ignore the RateLimiter of WaitStrategy

I would propose that you use - as in all other containers - the WaitStrategy.

  • Remove the override/method JdbcDatabaseContainer#waitUntilContainerStarted
  • Create a custom WaitStrategy called JDBCWaitStrategy. It could look like this:
    class JDBCWaitStrategy extends AbstractWaitStrategy
    {
    	@Override
    	protected void waitUntilReady()
    	{
    		if(!(this.waitStrategyTarget instanceof final JdbcDatabaseContainer<?> container))
    		{
    			throw new IllegalArgumentException(
    				"Container must implement JdbcDatabaseContainer");
    		}
    
    		try
    		{
    			Unreliables.retryUntilTrue(
    				(int)this.startupTimeout.getSeconds(),
    				TimeUnit.SECONDS,
    				() -> this.getRateLimiter().getWhenReady(() -> {
    					try(final Connection connection = container.createConnection("");
    						final Statement statement = connection.createStatement())
    					{
    						return statement.execute(container.getTestQueryString());
    					}
    				})
    			);
    		}
    		catch(final TimeoutException e)
    		{
    			throw new ContainerLaunchException(
    				"JDBCContainer cannot be accessed by (JDBC URL: "
    					+ container.getJdbcUrl()
    					+ "), please check container logs");
    		}
    	}
    }
    
  • Use the following default WaitStrategy for JDBCDatabaseContainer:
    new WaitAllStrategy()
    	.withStrategy(Wait.defaultWaitStrategy())
    	.withStrategy(new JDBCWaitStrategy())
    

Full example implementation:

  • https://github.com/xdev-software/tci-base/blob/13ca7984f6a732981cbd1912d9535076969004fa/tci-advanced-demo/tci-db/src/main/java/software/xdev/tci/demo/tci/db/containers/WaitableJDBCContainer.java
  • https://github.com/xdev-software/tci-base/blob/13ca7984f6a732981cbd1912d9535076969004fa/tci-advanced-demo/tci-db/src/main/java/software/xdev/tci/demo/tci/db/containers/DBContainer.java

AB-xdev avatar Jun 11 '25 13:06 AB-xdev

JDBC has a standard API: java.sql.Connection#isValid, so it would probably be a better choice by default.

vlsi avatar Jun 16 '25 06:06 vlsi