diff --git a/core/trino-main/src/main/java/io/trino/server/testing/TestingTrinoServer.java b/core/trino-main/src/main/java/io/trino/server/testing/TestingTrinoServer.java index ce3a6fddb579..4e51a76de52b 100644 --- a/core/trino-main/src/main/java/io/trino/server/testing/TestingTrinoServer.java +++ b/core/trino-main/src/main/java/io/trino/server/testing/TestingTrinoServer.java @@ -36,6 +36,7 @@ import io.airlift.jaxrs.JaxrsModule; import io.airlift.jmx.testing.TestingJmxModule; import io.airlift.json.JsonModule; +import io.airlift.log.Logger; import io.airlift.node.testing.TestingNodeModule; import io.airlift.tracetoken.TraceTokenModule; import io.trino.connector.CatalogName; @@ -96,6 +97,8 @@ import io.trino.testing.TestingWarningCollectorModule; import io.trino.transaction.TransactionManager; import io.trino.transaction.TransactionManagerModule; +import net.jodah.failsafe.Failsafe; +import net.jodah.failsafe.RetryPolicy; import org.weakref.jmx.guice.MBeanModule; import javax.annotation.concurrent.GuardedBy; @@ -120,6 +123,7 @@ import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Strings.nullToEmpty; +import static com.google.common.base.Throwables.getStackTraceAsString; import static com.google.common.io.MoreFiles.deleteRecursively; import static com.google.common.io.RecursiveDeleteOption.ALLOW_INSECURE; import static com.google.inject.util.Modules.EMPTY_MODULE; @@ -133,6 +137,8 @@ public class TestingTrinoServer implements Closeable { + private static final Logger log = Logger.get(TestingTrinoServer.class); + public static TestingTrinoServer create() { return builder().build(); @@ -286,17 +292,17 @@ private TestingTrinoServer( modules.add(additionalModule); - Bootstrap app = new Bootstrap(modules.build()); - Map optionalProperties = new HashMap<>(); environment.ifPresent(env -> optionalProperties.put("node.environment", env)); - injector = app - .doNotInitializeLogging() - .setRequiredConfigurationProperties(serverProperties.buildOrThrow()) - .setOptionalConfigurationProperties(optionalProperties) - .quiet() - .initialize(); + injector = Failsafe.with(new RetryPolicy<>() + .withMaxRetries(5) + .handleIf(throwable -> getStackTraceAsString(throwable).contains("BindException: Address already in use")) + .onRetry(event -> log.debug( + "Initialization failed on attempt %s, will retry. Exception: %s", + event.getAttemptCount(), + event.getLastFailure().getMessage()))) + .get(() -> initialize(serverProperties.buildOrThrow(), modules.build(), optionalProperties)); injector.getInstance(Announcer.class).start(); @@ -363,6 +369,16 @@ private TestingTrinoServer( refreshNodes(); } + private static Injector initialize(Map serverProperties, List modules, Map optionalProperties) + { + return new Bootstrap(modules) + .doNotInitializeLogging() + .setRequiredConfigurationProperties(serverProperties) + .setOptionalConfigurationProperties(optionalProperties) + .quiet() + .initialize(); + } + @Override public void close() throws IOException