From 88411eeabb69e0744c0baf117394ccf4a2e63d5c Mon Sep 17 00:00:00 2001 From: Ivan Kropotin <102463202+ivankrn@users.noreply.github.com> Date: Fri, 3 Jul 2026 21:20:08 +0500 Subject: [PATCH] Fix broken double-checked locking in the R2DBC connection factory Signed-off-by: Ivan Kropotin <102463202+ivankrn@users.noreply.github.com> --- .../TestcontainersR2DBCConnectionFactory.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java index bada076eec9..6cdc30b8305 100644 --- a/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java +++ b/modules/r2dbc/src/main/java/org/testcontainers/r2dbc/TestcontainersR2DBCConnectionFactory.java @@ -31,7 +31,7 @@ class TestcontainersR2DBCConnectionFactory implements ConnectionFactory, Closeab private final R2DBCDatabaseContainerProvider containerProvider; - private CompletableFuture future; + private volatile CompletableFuture future; TestcontainersR2DBCConnectionFactory(ConnectionFactoryOptions options) { this.options = options; @@ -47,10 +47,12 @@ class TestcontainersR2DBCConnectionFactory implements ConnectionFactory, Closeab @Override public Publisher create() { return new ConnectionPublisher(() -> { - if (future == null) { + CompletableFuture futureRef = future; + if (futureRef == null) { synchronized (this) { - if (future == null) { - future = + futureRef = future; + if (futureRef == null) { + futureRef = CompletableFuture.supplyAsync( () -> { R2DBCDatabaseContainer container = containerProvider.createContainer(options); @@ -59,12 +61,11 @@ public Publisher create() { }, EXECUTOR ); + future = futureRef; } } } - return future.thenApply(it -> { - return ConnectionFactories.find(it.configure(options)); - }); + return futureRef.thenApply(it -> ConnectionFactories.find(it.configure(options))); }); }