I can make a connection to the EMS queue from Spring, and it’s working fine with this configuration:
@Configuration
@EnableJms
public class TibcoJmsConfiguration {
public static final String SUN_AND_IBM_JSSE_SUPPORT = "j2se-default";
private final ParameterService parameterService;
private final ServerConfig serverConfig;
public TibcoJmsConfiguration(ParameterService parameterService, ServerConfig serverConfig) {
this.parameterService = parameterService;
this.serverConfig = serverConfig;
}
//based on TibcoJmsInitialContext.class
@Bean(name = "tibJmsConnectionFactory")
public ConnectionFactory connectionFactory() throws NamingException, JMSException {
// custom fault-tolerant system because url divided by comma not working:
// serverUrl = tcp://server0:7222,tcp://server1:7344
// workaround: use db value + restart jvm
String emsQueueUrl = parameterService.getEmsQueueUrl();
return getTibjmsConnectionFactory(emsQueueUrl);
}
@NotNull
private TibjmsConnectionFactory getTibjmsConnectionFactory(String emsQueueUrl) {
final TibjmsConnectionFactory connectionFactory = new TibjmsConnectionFactory(emsQueueUrl);
// https://docs.tibco.com/pub/ems/8.6.0/doc/html/GUID-CE5017DD-EF33-417A-AE0F-59DA05FA7BC7.html
connectionFactory.setConnAttemptCount(5);
connectionFactory.setConnAttemptDelay(1000);
connectionFactory.setConnAttemptTimeout(1000);
connectionFactory.setUserName(serverConfig.getConfigValue(CRM_USER));
connectionFactory.setUserPassword(serverConfig.getConfigValue(CRM_PWD));
connectionFactory.setSSLIdentity(serverConfig.getConfigValue(CRM_SSL_IDENTITY));
connectionFactory.setSSLPassword(serverConfig.getConfigValue(CRM_SSL_PASSWORD));
connectionFactory.setSSLDebugTrace(serverConfig.getConfigBoolean(CRM_DEBUG));
connectionFactory.setSSLTrace(serverConfig.getConfigBoolean(CRM_TRACE));
connectionFactory.setSSLTrustedCertificate(serverConfig.getConfigValue(CRM_SSL_TRUSTED));
connectionFactory.setSSLEnableVerifyHost(false);
connectionFactory.setSSLVendor(SUN_AND_IBM_JSSE_SUPPORT);
return connectionFactory;
}
@Bean
public BackOff getFixedBackOff(){
//block attempt connection
FixedBackOff backOff = new FixedBackOff();
backOff.setMaxAttempts(5);
backOff.setInterval(5000);
return backOff;
}
@Bean
public JmsListenerContainerFactory jmsListenerContainerFactory(@Qualifier("tibJmsConnectionFactory") ConnectionFactory connectionFactor) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactor);
factory.setBackOff(getFaultTolerantBackOff());
return factory;
}
public ConnectionFactory connectionFactory(String url) {
return getTibjmsConnectionFactory(url);
}
}
Where emsQueueUrl
is like ssl://ms-server-1:1234,ssl://ms-server-2:1234
.
At the start it even detects that if ms-server-1
is down to switch to ms-server-2
.
And I have a class with @JmsListener
which receives messages:
@Component
public class CrmEventReceiver {
private final CrmEventService crmEventService;
private final ServerConfig serverConfig;
private final ParameterService parameterService;
public CrmEventReceiver(CrmEventService crmEventService, ServerConfig serverConfig, ParameterService parameterService) {
this.crmEventService = crmEventService;
this.serverConfig = serverConfig;
this.parameterService = parameterService;
}
@JmsListener(destination = "AGPI.QL.MY_EVENT_INPUT")
public void receiveMessage(Object messageInput) {
try {
TextMessage message = (TextMessage) messageInput;
notNull(message, "[CRM_EVENT] TibcoJMSTextMessage - Could not receive message");
lEvent(message.getText());
} catch (Exception exception) {
LOGGER.error("[CRM_EVENT] TibcoJMSTextMessage - Could not convert message into TibjmsTextMessage", exception);
}
} else {
LOGGER.info("[CRM_EVENT] Message not read because the queue is not active");
}
}
}
The issue I have is if there is a switch/fail over from one EMS server to the second during the runtime then my listener fail. I would expect that the JMS reconnect out of the box to the secondary server but that it’s not the case. It loops over and over on the server that is off. The only way I found to stop the retry loop is by using
FixedBackOff
.
Do you know how to configure Spring & Tibco JMS to switch automatically from one server to another one during a ‘disaster recovery’?
I tried multiple EMS/queue configurations, creating my own custom FixedBackOff
class to live reload the JMS listener on the second server, but none of my tentative solutions worked.
3