I am upgrading to Spring boot version 2.3.1.Release. So, there is a major change in Spring Data Cassandra due to Java driver version upgrade to v4. I am stuck on application startup because there is a DriverTimeout exception being thrown:
com.datastax.oss.driver.api.core.DriverTimeoutException: [s0|control|id: 0x8572a9d7, L:/My_IPv4:Random_Port - R:/Cassandra_Server:Port] Protocol initialization request, step 1 (OPTIONS): timed out after 500 ms
My cassandra configuration:
#Bean(name = "mySession")
#Primary
public CqlSession session() {
String containerIpAddress = getContactPoints();
int containerPort = getPort();
InetSocketAddress containerEndPoint = new InetSocketAddress(containerIpAddress, containerPort);
return CqlSession.builder().withLocalDatacenter(getLocalDataCenter())
.addContactPoint(containerEndPoint)
.withAuthCredentials(dbProperties.getCassandraUserName(), dbProperties.getCassandraPassword())
.withKeyspace(getKeyspaceName()).build();
}
I have also tried using DriverConfigLoader option by explicitly setting connection timeout as:
#Bean(name = "mySession")
#Primary
public CqlSession session() {
String containerIpAddress = getContactPoints();
int containerPort = getPort();
InetSocketAddress containerEndPoint = new InetSocketAddress(containerIpAddress, containerPort);
DriverConfigLoader loader =
DriverConfigLoader.programmaticBuilder()
.withDuration(DefaultDriverOption.CONNECTION_CONNECT_TIMEOUT, Duration.ofSeconds(5))
.build();
return CqlSession.builder().withLocalDatacenter(getLocalDataCenter())
.withConfigLoader(loader)
.addContactPoint(containerEndPoint)
.withAuthCredentials(dbProperties.getCassandraUserName(), dbProperties.getCassandraPassword())
.withKeyspace(getKeyspaceName()).build();
}
, but to no avail and same exception is being thrown. My current Spring boot version is 2.2.0.Release and I am not even specifying any timeout there and its working fine. How can this issue be fixed?
Assuming that you are using spring-data-cassandra. You can either configure it entirely through your application properties.
Alternatively you can go the route that you're going and build out your own session. If you're doing it that way, you may want to turn off Spring's autoconfiguration.
#EnableAutoConfiguration(exclude = {
CassandraDataAutoConfiguration.class })
and then instead of building the CqlSession, use the CqlSessionFactory like:
#Primary
#Bean("mySessionFactory")
public CqlSessionFactoryBean getCqlSession() {
CqlSessionFactoryBean factory = new CqlSessionFactoryBean();
factory.setUsername(userName);
factory.setPassword(password);
factory.setPort(port);
factory.setKeyspaceName(keyspaceName);
factory.setContactPoints(hostList);
factory.setLocalDatacenter(datacenter);
return factory;
}
Related
I am trying to understand how I can shutdown the connection to mongo while my java application runs for tesing purposes. I am trying to see how my application would behave in case mongo is unavailable. Is there any way this accomplished at the application level without touching the mongo database?. This is the class I use to create the mongo connection
#Configuration
#EnableMongoAuditing
public class MongoConfiguration {
#Autowired
private MongoProperties mongoProperties;
#Bean
public MongoClient mongo(){
ConnectionString connectionString = new ConnectionString(mongoProperties.getUri());
MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.applyConnectionString(connectionString)
.build();
return MongoClients.create(mongoClientSettings);
}
// to use #Transactional -- supporting spring data transaction support in MongoDB
#Bean
MongoTransactionManager transactionManager(MongoDbFactory dbFactory){
return new MongoTransactionManager(dbFactory);
}
#Primary
#Bean(name = "mongoTemplate")
public MongoTemplate mongoTemplate(){
return new MongoTemplate(mongo(), mongoProperties.getDatabase());
}
}
You can use fail points. See https://github.com/mongodb/specifications/tree/master/source/transactions/tests#failcommand for examples and you need to start the server with --setParameter enableTestCommands=1.
I am getting Unable to connect to Redis;nested exception is io.lettuce.core.RedisConnectionException using RedisTempalte error when i try to connect azure redis cache from my spring reactive application.
I have configured below in properties file
spring.redis.host=hostName
spring.redis.port=6379
spring.redis.password=password
also tried java based configuration using LettuceConnectionFactory
I have encountered the same problem when enabling password authentication in AWS ElastiCache because of not using SSL for the Redis client.
Bellow RedisConfig.java uses SSL to connect and my error disappeared. I am using Spring Reactive by the way.
#Configuration
#ConfigurationProperties(prefix = "spring.redis")
#Setter
public class RedisConfig {
private String host;
private String password;
#Bean
#Primary
public ReactiveRedisConnectionFactory reactiveRedisConnectionFactory(RedisConfiguration defaultRedisConfig) {
LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
.useSsl().and()
.commandTimeout(Duration.ofMillis(60000)).build();
return new LettuceConnectionFactory(defaultRedisConfig, clientConfig);
}
#Bean
public RedisConfiguration defaultRedisConfig() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName(host);
config.setPassword(RedisPassword.of(password));
return config;
}
}
I'm developing Spring Boot application which must connect to several WebSphere JMS connections with different ports or even ip addresses. I need receive and send messages to different queues.
I took example of connection from this source - https://github.com/lzp4ever/IBM_WebSphere_MQ_Spring_Boot_JMS
But when i add second connectionFactory Spring Boot failes to start, it just don't know which once to use.
My question is How should i configure my config file to listen several queues? Is it good idea connecting SpringBoot app to several different JMS servers?
Solution
i just copy and paste same beans(like at git link above) second time and add Bean(name) to separate them. It was not work and then i added new JmsListenerContainerFactory bean to each of my config file.
One of my config file is:
#Bean(name = "mqQueueConnectionFactory2")
public MQQueueConnectionFactory mqQueueConnectionFactory2() {
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
mqQueueConnectionFactory.setHostName(host);
try {
mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
mqQueueConnectionFactory.setCCSID(1208);
mqQueueConnectionFactory.setChannel(channel);
mqQueueConnectionFactory.setPort(port);
mqQueueConnectionFactory.setQueueManager(queueManager);
} catch (Exception e) {
logger.error("MQQueueConnectionFactory bean exception", e);
}
return mqQueueConnectionFactory;
}
#Bean(name = "userCredentialsConnectionFactoryAdapter2")
UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter2(#Qualifier("mqQueueConnectionFactory2") MQQueueConnectionFactory mqQueueConnectionFactory) {
UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter = new UserCredentialsConnectionFactoryAdapter();
userCredentialsConnectionFactoryAdapter.setUsername(username);
userCredentialsConnectionFactoryAdapter.setPassword(password);
userCredentialsConnectionFactoryAdapter.setTargetConnectionFactory(mqQueueConnectionFactory);
return userCredentialsConnectionFactoryAdapter;
}
#Bean(name = "cachingConnectionFactory2")
//#Primary
public CachingConnectionFactory cachingConnectionFactory2(#Qualifier("userCredentialsConnectionFactoryAdapter2") UserCredentialsConnectionFactoryAdapter userCredentialsConnectionFactoryAdapter) {
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory();
cachingConnectionFactory.setTargetConnectionFactory(userCredentialsConnectionFactoryAdapter);
cachingConnectionFactory.setSessionCacheSize(500);
cachingConnectionFactory.setReconnectOnException(true);
return cachingConnectionFactory;
}
#Bean(name = "jmsTransactionManager2")
public PlatformTransactionManager jmsTransactionManager2(#Qualifier("cachingConnectionFactory2") CachingConnectionFactory cachingConnectionFactory) {
JmsTransactionManager jmsTransactionManager = new JmsTransactionManager();
jmsTransactionManager.setConnectionFactory(cachingConnectionFactory);
return jmsTransactionManager;
}
#Bean(name = "jmsOperations2")
public JmsOperations jmsOperations2(#Qualifier("cachingConnectionFactory2") CachingConnectionFactory cachingConnectionFactory) {
JmsTemplate jmsTemplate = new JmsTemplate(cachingConnectionFactory);
jmsTemplate.setReceiveTimeout(receiveTimeout);
return jmsTemplate;
}
#Bean
public JmsListenerContainerFactory<?> myFactory2(#Qualifier("cachingConnectionFactory2") CachingConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all boot's default to this factory, including the message converter
configurer.configure(factory, connectionFactory);
// You could still override some of Boot's default if necessary.
return factory;
}
Then i change my sender code from this:
#Autowired
private JmsOperations jmsOperations;
to this
#Autowired
#Qualifier("jmsOperations2")
private JmsOperations jmsOperations;
also i change my receiver to:
#JmsListener(destination = "${project.queues.uzb.recieve}", containerFactory = "myFactory2")
public void receiveMessage(JMSTextMessage data) {
}
it seems to me it worked!!!
But one of my CachingConnectionFactory must be marked as #Primary. If i delete #Primaty from one of my config files then i am gettig this error:
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2018-03-28 12:28:37 -
APPLICATION FAILED TO START
Description:
Parameter 1 of method myFactory in com.config.UzbConnection required a bean of type 'org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer' in your configuration.
Thanks
Just my 2 cents. If you have problems with multiple JMS connections because you have a project using a mix of Spring-boot and JMS with Spring xml configuration to make your connection factory, you can disable autostart of spring-boot-jms with this in your application:
#SpringBootApplication(exclude = {JmsAutoConfiguration.class})
this way you can mix both.
How can I configure a spring boot config client microservice to fetch its configuration from an OAuth2 configServer which is #EnableResourceServer ?
I have one OAuth2 Authorization server (#EnableAuthorizationServer). There is a configServer (#EnableConfigServer) which I have configured to respond only to valid requests authorized by authorization server containing JWT tokens.
There is also a microservice client APP1 of the config server which needs to fetch its configuration upon startup from the aforementioned config server. Since the server only responds to requests containing valid access tokens (jwt tokens) I tried to inject OAuth2RestTemplate into ConfigServicePropertySourceLocator so that my config client (APP1) could fetch its config.
In order to do that I tried the partial solution which was discussed here.
This is my OAuth2 ready RestTemplate that I want to inject
#Configuration
public class OAuthConfig {
#Bean
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details) {
return new OAuth2RestTemplate(details, oauth2ClientContext);
}}
and this is my custom property locator
public class CustomConfigServicePropertySourceLocator {
#Autowired
private ConfigurableEnvironment environment;
#Autowired
private RestTemplate restTemplate;
#Bean
public ConfigClientProperties configClientProperties() {
ConfigClientProperties client = new ConfigClientProperties(this.environment);
client.setEnabled(false);
return client;
}
#Bean
#Primary
public ConfigServicePropertySourceLocator configServicePropertySourceLocator() {
ConfigClientProperties clientProperties = configClientProperties();
ConfigServicePropertySourceLocator configServicePropertySourceLocator = new ConfigServicePropertySourceLocator(
clientProperties);
configServicePropertySourceLocator.setRestTemplate(restTemplate);
return configServicePropertySourceLocator;
}}
I Followed the instructions in Customizing the Bootstrap Configuration
I created a META_INF > spring.factories file containing
org.springframework.cloud.bootstrap.BootstrapConfiguration=com.company.mcapp.CustomConfigServicePropertySourceLocator
By debugging I can see that this custom locator will get called but my APP1 is failing to contact config server to fetch the configurations.
In initialize method of PropertySourceBootstrapConfiguration (below) I can see that the propertySourceLocators does not contain my CustomConfigServicePropertySourceLocator.
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
CompositePropertySource composite = new CompositePropertySource(
BOOTSTRAP_PROPERTY_SOURCE_NAME);
AnnotationAwareOrderComparator.sort(this.propertySourceLocators);
boolean empty = true;
ConfigurableEnvironment environment = applicationContext.getEnvironment();
for (PropertySourceLocator locator : this.propertySourceLocators) {
PropertySource<?> source = null;
source = locator.locate(environment);
if (source == null) {
continue;
}
logger.info("Located property source: " + source);
composite.addPropertySource(source);
empty = false;
}
.
.
.
UPDATE: The issue was a silly mistake That I made. Instead of creating META-INF I created META_INF.
Is it possible to load spring context with #RabbitListener even if RabbitMQ message broker is down?
The behavior should be similar as in case of broker disconnection. Application is waiting for broker and when it is restored, then listerner is automaticaly reconnected.
Spring Boot 1.3.2.RELEASE
GitHub demo project
spring-amqp configuration:
#Bean
public MessageConverter jsonMessageConverter() {
return new JsonMessageConverter();
}
#Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
return connectionFactory;
}
#Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setConcurrentConsumers(10);
factory.setMaxConcurrentConsumers(10);
factory.setMessageConverter(jsonMessageConverter());
return factory;
}
#Bean
public AmqpAdmin amqpAdmin() {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory());
rabbitAdmin.setIgnoreDeclarationExceptions(true); // useless
return rabbitAdmin;
}
listener configuration:
#Service
public class CalculatorServiceV2 {
#RabbitListener(bindings = #QueueBinding(
value = #Queue(value = "calc_service_v2.multiply", durable = "false", autoDelete = "true"),
exchange = #Exchange(value = "calc_service_v2", durable = "false", autoDelete = "true"),
key = "multiply"))
public Result multiply(Operands operands) {
// do something..
}
}
What version of Spring AMQP are you using?
Can you provide a stack trace? (edit the question, don't try to put it in a comment).
I just ran a test and it works as expected; the listener container attempts to reconnect every 5 seconds (the default recovery interval).
rabbitAdmin.setIgnoreDeclarationExceptions(true); // useless
In 1.6 (currently at milestone 1) we've changed that boolean to skip all exceptions; previously it only applied to exceptions caused by errors returned from the broker.
However, the admin won't attempt to declare the elements until the connection is established so that should be moot in this context.
I need to see a stack trace to understand what's going on in your case.