mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Use ephemeral port for Hazelcast
When Hazelcast is started on a fixed port and that port is already in use, it does not fail to start which makes the problem hard to detect. A symptom of the problem is that clients will not be able to connect and will either retry indefinitely or will timeout depending on their configuration. This commit updates the Hazelcast client tests to start the Hazelcast instance on an ephemeral port and to customize the client configuration with the instance's address before use. This should allow the client tests to work reliably in an environment where Hazelcast's default port is already in use. Closes gh-35903
This commit is contained in:
parent
63978978b4
commit
088006ff60
@ -16,10 +16,16 @@
|
|||||||
|
|
||||||
package org.springframework.boot.autoconfigure.hazelcast;
|
package org.springframework.boot.autoconfigure.hazelcast;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
import com.hazelcast.client.HazelcastClient;
|
import com.hazelcast.client.HazelcastClient;
|
||||||
import com.hazelcast.client.config.ClientConfig;
|
import com.hazelcast.client.config.ClientConfig;
|
||||||
import com.hazelcast.client.config.ClientConnectionStrategyConfig;
|
|
||||||
import com.hazelcast.client.config.ConnectionRetryConfig;
|
|
||||||
import com.hazelcast.client.impl.clientside.HazelcastClientProxy;
|
import com.hazelcast.client.impl.clientside.HazelcastClientProxy;
|
||||||
import com.hazelcast.config.Config;
|
import com.hazelcast.config.Config;
|
||||||
import com.hazelcast.core.Hazelcast;
|
import com.hazelcast.core.Hazelcast;
|
||||||
@ -36,6 +42,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|||||||
import org.springframework.boot.test.context.runner.ContextConsumer;
|
import org.springframework.boot.test.context.runner.ContextConsumer;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@ -52,9 +59,15 @@ class HazelcastAutoConfigurationClientTests {
|
|||||||
*/
|
*/
|
||||||
private static HazelcastInstance hazelcastServer;
|
private static HazelcastInstance hazelcastServer;
|
||||||
|
|
||||||
|
private static String endpointAddress;
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
static void init() {
|
static void init() {
|
||||||
hazelcastServer = Hazelcast.newHazelcastInstance();
|
Config config = Config.load();
|
||||||
|
config.getNetworkConfig().setPort(0);
|
||||||
|
hazelcastServer = Hazelcast.newHazelcastInstance(config);
|
||||||
|
InetSocketAddress inetSocketAddress = (InetSocketAddress) hazelcastServer.getLocalEndpoint().getSocketAddress();
|
||||||
|
endpointAddress = inetSocketAddress.getHostString() + ":" + inetSocketAddress.getPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
@ -69,73 +82,52 @@ class HazelcastAutoConfigurationClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void systemPropertyWithXml() {
|
void systemPropertyWithXml() {
|
||||||
|
File config = prepareConfiguration("src/test/resources/org/springframework/"
|
||||||
|
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.xml");
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY
|
.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY + "=" + config.getAbsolutePath())
|
||||||
+ "=classpath:org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.xml")
|
|
||||||
.run(assertSpecificHazelcastClient("explicit-xml"));
|
.run(assertSpecificHazelcastClient("explicit-xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void systemPropertyWithYaml() {
|
void systemPropertyWithYaml() {
|
||||||
|
File config = prepareConfiguration("src/test/resources/org/springframework/"
|
||||||
|
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.yaml");
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY
|
.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY + "=" + config.getAbsolutePath())
|
||||||
+ "=classpath:org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.yaml")
|
|
||||||
.run(assertSpecificHazelcastClient("explicit-yaml"));
|
.run(assertSpecificHazelcastClient("explicit-yaml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void systemPropertyWithYml() {
|
void systemPropertyWithYml() {
|
||||||
|
File config = prepareConfiguration("src/test/resources/org/springframework/"
|
||||||
|
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.yml");
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY
|
.withSystemProperties(HazelcastClientConfiguration.CONFIG_SYSTEM_PROPERTY + "=" + config.getAbsolutePath())
|
||||||
+ "=classpath:org/springframework/boot/autoconfigure/hazelcast/hazelcast-client-specific.yml")
|
|
||||||
.run(assertSpecificHazelcastClient("explicit-yml"));
|
.run(assertSpecificHazelcastClient("explicit-yml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void explicitConfigFileWithXml() {
|
void explicitConfigUrlWithXml() throws MalformedURLException {
|
||||||
this.contextRunner
|
File config = prepareConfiguration("src/test/resources/org/springframework/"
|
||||||
.withPropertyValues("spring.hazelcast.config=org/springframework/boot/autoconfigure/"
|
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.xml");
|
||||||
+ "hazelcast/hazelcast-client-specific.xml")
|
this.contextRunner.withPropertyValues("spring.hazelcast.config=" + config.toURI().toURL())
|
||||||
.run(assertSpecificHazelcastClient("explicit-xml"));
|
.run(assertSpecificHazelcastClient("explicit-xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void explicitConfigFileWithYaml() {
|
void explicitConfigUrlWithYaml() throws MalformedURLException {
|
||||||
this.contextRunner
|
File config = prepareConfiguration("src/test/resources/org/springframework/"
|
||||||
.withPropertyValues("spring.hazelcast.config=org/springframework/boot/autoconfigure/"
|
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.yaml");
|
||||||
+ "hazelcast/hazelcast-client-specific.yaml")
|
this.contextRunner.withPropertyValues("spring.hazelcast.config=" + config.toURI().toURL())
|
||||||
.run(assertSpecificHazelcastClient("explicit-yaml"));
|
.run(assertSpecificHazelcastClient("explicit-yaml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void explicitConfigFileWithYml() {
|
void explicitConfigUrlWithYml() throws MalformedURLException {
|
||||||
this.contextRunner
|
File config = prepareConfiguration("src/test/resources/org/springframework/"
|
||||||
.withPropertyValues("spring.hazelcast.config=org/springframework/boot/autoconfigure/"
|
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.yml");
|
||||||
+ "hazelcast/hazelcast-client-specific.yml")
|
this.contextRunner.withPropertyValues("spring.hazelcast.config=" + config.toURI().toURL())
|
||||||
.run(assertSpecificHazelcastClient("explicit-yml"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void explicitConfigUrlWithXml() {
|
|
||||||
this.contextRunner
|
|
||||||
.withPropertyValues("spring.hazelcast.config=classpath:org/springframework/"
|
|
||||||
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.xml")
|
|
||||||
.run(assertSpecificHazelcastClient("explicit-xml"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void explicitConfigUrlWithYaml() {
|
|
||||||
this.contextRunner
|
|
||||||
.withPropertyValues("spring.hazelcast.config=classpath:org/springframework/"
|
|
||||||
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.yaml")
|
|
||||||
.run(assertSpecificHazelcastClient("explicit-yaml"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void explicitConfigUrlWithYml() {
|
|
||||||
this.contextRunner
|
|
||||||
.withPropertyValues("spring.hazelcast.config=classpath:org/springframework/"
|
|
||||||
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.yml")
|
|
||||||
.run(assertSpecificHazelcastClient("explicit-yml"));
|
.run(assertSpecificHazelcastClient("explicit-yml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,28 +148,26 @@ class HazelcastAutoConfigurationClientTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void clientConfigWithInstanceNameCreatesClientIfNecessary() {
|
void clientConfigWithInstanceNameCreatesClientIfNecessary() throws MalformedURLException {
|
||||||
assertThat(HazelcastClient.getHazelcastClientByName("spring-boot")).isNull();
|
assertThat(HazelcastClient.getHazelcastClientByName("spring-boot")).isNull();
|
||||||
this.contextRunner
|
File config = prepareConfiguration("src/test/resources/org/springframework/"
|
||||||
.withPropertyValues("spring.hazelcast.config=classpath:org/springframework/"
|
+ "boot/autoconfigure/hazelcast/hazelcast-client-instance.xml");
|
||||||
+ "boot/autoconfigure/hazelcast/hazelcast-client-instance.xml")
|
this.contextRunner.withPropertyValues("spring.hazelcast.config=" + config.toURI().toURL())
|
||||||
.run((context) -> assertThat(context).getBean(HazelcastInstance.class)
|
.run((context) -> assertThat(context).getBean(HazelcastInstance.class)
|
||||||
.extracting(HazelcastInstance::getName)
|
.extracting(HazelcastInstance::getName)
|
||||||
.isEqualTo("spring-boot"));
|
.isEqualTo("spring-boot"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void autoConfiguredClientConfigUsesApplicationClassLoader() {
|
void autoConfiguredClientConfigUsesApplicationClassLoader() throws MalformedURLException {
|
||||||
this.contextRunner
|
File config = prepareConfiguration("src/test/resources/org/springframework/"
|
||||||
.withPropertyValues("spring.hazelcast.config=org/springframework/boot/autoconfigure/"
|
+ "boot/autoconfigure/hazelcast/hazelcast-client-specific.xml");
|
||||||
+ "hazelcast/hazelcast-client-specific.xml")
|
this.contextRunner.withPropertyValues("spring.hazelcast.config=" + config.toURI().toURL()).run((context) -> {
|
||||||
.run((context) -> {
|
HazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);
|
||||||
HazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);
|
assertThat(hazelcast).isInstanceOf(HazelcastClientProxy.class);
|
||||||
assertThat(hazelcast).isInstanceOf(HazelcastClientProxy.class);
|
ClientConfig clientConfig = ((HazelcastClientProxy) hazelcast).getClientConfig();
|
||||||
ClientConfig clientConfig = ((HazelcastClientProxy) hazelcast).getClientConfig();
|
assertThat(clientConfig.getClassLoader()).isSameAs(context.getSourceApplicationContext().getClassLoader());
|
||||||
assertThat(clientConfig.getClassLoader())
|
});
|
||||||
.isSameAs(context.getSourceApplicationContext().getClassLoader());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ContextConsumer<AssertableApplicationContext> assertSpecificHazelcastClient(String label) {
|
private ContextConsumer<AssertableApplicationContext> assertSpecificHazelcastClient(String label) {
|
||||||
@ -193,6 +183,22 @@ class HazelcastAutoConfigurationClientTests {
|
|||||||
.anyMatch((e) -> e.equals(label)), "Label equals to " + label);
|
.anyMatch((e) -> e.equals(label)), "Label equals to " + label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private File prepareConfiguration(String input) {
|
||||||
|
File configFile = new File(input);
|
||||||
|
try {
|
||||||
|
String config = FileCopyUtils.copyToString(new FileReader(configFile));
|
||||||
|
config = config.replace("${address}", endpointAddress);
|
||||||
|
System.out.println(config);
|
||||||
|
File outputFile = new File(Files.createTempDirectory(getClass().getSimpleName()).toFile(),
|
||||||
|
configFile.getName());
|
||||||
|
FileCopyUtils.copy(config, new FileWriter(outputFile));
|
||||||
|
return outputFile;
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
static class HazelcastServerAndClientConfig {
|
static class HazelcastServerAndClientConfig {
|
||||||
|
|
||||||
@ -203,8 +209,10 @@ class HazelcastAutoConfigurationClientTests {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
ClientConfig clientConfig() {
|
ClientConfig clientConfig() {
|
||||||
return new ClientConfig().setConnectionStrategyConfig(new ClientConnectionStrategyConfig()
|
ClientConfig config = new ClientConfig();
|
||||||
.setConnectionRetryConfig(new ConnectionRetryConfig().setClusterConnectTimeoutMillis(60000)));
|
config.getConnectionStrategyConfig().getConnectionRetryConfig().setClusterConnectTimeoutMillis(60000);
|
||||||
|
config.getNetworkConfig().getAddresses().add(endpointAddress);
|
||||||
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,5 +10,11 @@
|
|||||||
<cluster-connect-timeout-millis>60000</cluster-connect-timeout-millis>
|
<cluster-connect-timeout-millis>60000</cluster-connect-timeout-millis>
|
||||||
</connection-retry>
|
</connection-retry>
|
||||||
</connection-strategy>
|
</connection-strategy>
|
||||||
|
|
||||||
|
<network>
|
||||||
|
<cluster-members>
|
||||||
|
<address>${address}</address>
|
||||||
|
</cluster-members>
|
||||||
|
</network>
|
||||||
|
|
||||||
</hazelcast-client>
|
</hazelcast-client>
|
||||||
|
@ -10,5 +10,9 @@
|
|||||||
<cluster-connect-timeout-millis>60000</cluster-connect-timeout-millis>
|
<cluster-connect-timeout-millis>60000</cluster-connect-timeout-millis>
|
||||||
</connection-retry>
|
</connection-retry>
|
||||||
</connection-strategy>
|
</connection-strategy>
|
||||||
|
<network>
|
||||||
|
<cluster-members>
|
||||||
|
<address>${address}</address>
|
||||||
|
</cluster-members>
|
||||||
|
</network>
|
||||||
</hazelcast-client>
|
</hazelcast-client>
|
||||||
|
@ -4,3 +4,6 @@ hazelcast-client:
|
|||||||
connection-strategy:
|
connection-strategy:
|
||||||
connection-retry:
|
connection-retry:
|
||||||
cluster-connect-timeout-millis: 60000
|
cluster-connect-timeout-millis: 60000
|
||||||
|
network:
|
||||||
|
cluster-members:
|
||||||
|
- ${address}
|
@ -4,3 +4,6 @@ hazelcast-client:
|
|||||||
connection-strategy:
|
connection-strategy:
|
||||||
connection-retry:
|
connection-retry:
|
||||||
cluster-connect-timeout-millis: 60000
|
cluster-connect-timeout-millis: 60000
|
||||||
|
network:
|
||||||
|
cluster-members:
|
||||||
|
- ${address}
|
||||||
|
Loading…
Reference in New Issue
Block a user