自定义IBM MQ的自动重连接设置



我已经写了一个代码连接到IBM MQ,我使用ConnectionNameList自动重新连接到IBM MQ。

我想自定义隐式发生的重连接。我在网上查了很多文章,可就是看不懂。

这是我的队列管理器配置:
@Configuration
public class QM1Config{

public String queueManager;
public String queue;
public String channel;
public String connName;
public String user;
public String password;
private static final int RECONNECT_TIMEOUT = 10;

@Autowired
MQService config;

@Bean
public MQConnectionFactory mqQueueConnectionFactory() {
this.channel = config.getHosts().get(0).getChannel();
this.user = config.getHosts().get(0).getUser();
this.password = config.getHosts().get(0).getPassword();
this.queueManager = config.getHosts().get(0).getQueueManager();
this.queue = config.getHosts().get(0).getQueue();
this.connName = config.getHosts().get(0).getConnName();
System.out.println(channel+" "+connName+" "+queueManager+" "+user);
MQConnectionFactory mqQueueConnectionFactory = new MQConnectionFactory();
try {
mqQueueConnectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
mqQueueConnectionFactory.setBooleanProperty(WMQConstants.USER_AUTHENTICATION_MQCSP, false);
mqQueueConnectionFactory.setCCSID(1208);
mqQueueConnectionFactory.setChannel(channel);
mqQueueConnectionFactory.setStringProperty(WMQConstants.USERID, user);
mqQueueConnectionFactory.setStringProperty(WMQConstants.PASSWORD, password);
mqQueueConnectionFactory.setQueueManager(queueManager);
mqQueueConnectionFactory.setConnectionNameList(connName);
} catch (Exception e) {
e.printStackTrace();


}
return mqQueueConnectionFactory;

}

@Bean
public JmsListenerContainerFactory<?> qm1JmsListenerContainerFactory(@Qualifier("mqQueueConnectionFactory") MQConnectionFactory mqQueueConnectionFactory, DefaultJmsListenerContainerFactoryConfigurer configurer) throws InterruptedException {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
this.queue = config.getHosts().get(0).getQueue();
configurer.configure(factory, mqQueueConnectionFactory);
return factory;
}
@Bean("jmsTemplate1")
public JmsTemplate jmsTemplate(@Qualifier("mqQueueConnectionFactory") MQConnectionFactory mqQueueConnectionFactory) {
JmsTemplate jmsTemplate1  = new JmsTemplate(mqQueueConnectionFactory);
return jmsTemplate1;
}

}

当我停止队列管理器时,我每5秒得到以下异常:

2022-04-24 01:17:43.194  WARN 6644 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : Setup of JMS message listener invoker failed for destination 'Q5' - trying to recover. Cause: JMSWMQ2002: Failed to get a message from destination 'Q5'.; nested exception is com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2009' ('MQRC_CONNECTION_BROKEN').
2022-04-24 01:17:43.232 ERROR 6644 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : Could not refresh JMS Connection for destination 'Q5' - retrying using FixedBackOff{interval=5000, currentAttempts=0, maxAttempts=unlimited}. Cause: JMSWMQ0018: Failed to connect to queue manager 'QM5' with connection mode 'Client' and host name 'Client'.; nested exception is com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2059' ('MQRC_Q_MGR_NOT_AVAILABLE').
2022-04-24 01:17:48.243 ERROR 6644 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : Could not refresh JMS Connection for destination 'Q5' - retrying using FixedBackOff{interval=5000, currentAttempts=1, maxAttempts=unlimited}. Cause: JMSWMQ0018: Failed to connect to queue manager 'QM5' with connection mode 'Client' and host name 'Client'.; nested exception is com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2538' ('MQRC_HOST_NOT_AVAILABLE').
2022-04-24 01:17:53.245 ERROR 6644 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : Could not refresh JMS Connection for destination 'Q5' - retrying using FixedBackOff{interval=5000, currentAttempts=2, maxAttempts=unlimited}. Cause: JMSWMQ0018: Failed to connect to queue manager 'QM5' with connection mode 'Client' and host name 'Client'.; nested exception is com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2538' ('MQRC_HOST_NOT_AVAILABLE').
2022-04-24 01:17:58.250 ERROR 6644 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : Could not refresh JMS Connection for destination 'Q5' - retrying using FixedBackOff{interval=5000, currentAttempts=3, maxAttempts=unlimited}. Cause: JMSWMQ0018: Failed to connect to queue manager 'QM5' with connection mode 'Client' and host name 'Client'.; nested exception is com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2538' ('MQRC_HOST_NOT_AVAILABLE').

所以我希望前3次重新连接尝试应该是一个警告消息,而不是错误消息,如上面的日志和第4次尝试所示,我希望它是一个错误消息。并且每10/15秒重新连接一次。

如何配置这些重连接设置?

任何帮助都将非常感激!谢谢!

编辑:我添加了一个异常监听器,如下所示:

public class MQExceptionListener implements ExceptionListener {
private static final Logger LOGGER = LoggerFactory.getLogger(MQExceptionListener.class);
int count = -1;

@Override
public void onException(JMSException ex) {

if(count > 2) {
System.out.println("COUNT - "+ count);
count++;
LOGGER.error("***********************************************");
LOGGER.error(ex.toString()+" THIS IS EX TO STRING");
if (ex.getLinkedException() != null) {
LOGGER.error(ex.getLinkedException().toString()+" THIS IS getLinkedException TO STRING");
}
LOGGER.error("================================================");
}else {
System.out.println("COUNT - "+ count);
count++;
LOGGER.warn("***********************************************");
LOGGER.warn(ex.toString()+" THIS IS EX TO STRING");
if (ex.getLinkedException() != null) {
LOGGER.warn(ex.getLinkedException().toString()+" THIS IS getLinkedException TO STRING");
}
LOGGER.warn("================================================");

}

}
}

现在我的日志如下:

COUNT - 1
2022-04-24 14:41:04.905  WARN 9268 --- [enerContainer-1] com.mq.sslMQ.MQExceptionListener         : ***********************************************
2022-04-24 14:41:04.905  WARN 9268 --- [enerContainer-1] com.mq.sslMQ.MQExceptionListener         : com.ibm.msg.client.jms.DetailedIllegalStateException: JMSWMQ0018: Failed to connect to queue manager 'QM5' with connection mode 'Client' and host name 'Client'.
Check the queue manager is started and if running in client mode, check there is a listener running. Please see the linked exception for more information. THIS IS EX TO STRING
2022-04-24 14:41:04.905  WARN 9268 --- [enerContainer-1] com.mq.sslMQ.MQExceptionListener         : com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2538' ('MQRC_HOST_NOT_AVAILABLE'). THIS IS getLinkedException TO STRING
2022-04-24 14:41:04.905  WARN 9268 --- [enerContainer-1] com.mq.sslMQ.MQExceptionListener         : ================================================
2022-04-24 14:41:04.905 ERROR 9268 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : Could not refresh JMS Connection for destination 'Q5' - retrying using FixedBackOff{interval=5000, currentAttempts=1, maxAttempts=unlimited}. Cause: JMSWMQ0018: Failed to connect to queue manager 'QM5' with connection mode 'Client' and host name 'Client'.; nested exception is com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2538' ('MQRC_HOST_NOT_AVAILABLE').

我不希望默认的消息侦听器容器日志被打印到控制台。我们如何做到这一点?

IBM文档中说:-

默认情况下,每隔一段时间重新连接一次:

  • 第一次尝试是在初始延迟1秒后进行的,加上250毫秒的随机元素。
  • 第一次尝试失败后,第二次尝试在2秒内进行,加上一个随机间隔,最长500毫秒。
  • 第二次尝试失败后,在4秒内进行第三次尝试,再加上一个不超过1秒的随机间隔。
  • 第三次尝试失败后,在8秒内进行第四次尝试,再加上一个不超过2秒的随机间隔。
  • 第4次尝试失败后,第5次尝试的时间间隔为16秒,再加上最长4秒的随机间隔。
  • 第6次尝试以及所有后续尝试都是在25秒内进行的,加上前一次尝试失败后的随机间隔(最多6秒和250毫秒)。

重连接尝试的延迟间隔部分是固定的,部分是随机的。这是为了防止连接到不再可用的队列管理器的JMS应用程序的所有IBM MQ类同时重新连接。

如果需要增加默认值,以更准确地反映队列管理器恢复或备用队列管理器变为活动所需的时间,请修改客户端配置文件Channel节中的ReconDelay属性。

你可以在这里阅读更多关于这个属性的信息。

听起来您需要将以下内容放入您的mqclient.ini文件中。

CHANNELS:
ReconDelay=(10000,5000)

请求10秒的延迟加上5秒的随机元素,这是我对你请求10/15秒的解释。您没有要求任何重新连接尝试在时间上不同,尽管您可以在需要时这样做。

注意,不能更改消息的WARN/ERROR状态。

请记住,您总是可以关闭自动重新连接,并通过捕获应用程序中的连接失败来实现您自己需要的任何功能。自动重新连接是为不能(或不愿意)捕获连接失败的应用程序设计的。

我想补充一下,5秒间隔的重新连接尝试是DefaultMessageListenerContainer试图重新连接。默认的重新连接间隔是5秒-DEFAULT_RECOVERY_INTERVAL,所以我不认为这涉及MQ重新连接机制。

使用上面列出的异常处理程序,您可以编程地更改DefaultMessageListenerContainersetRecoveryInterval()或使用setBackOff()来控制回退间隔。

要禁用日志记录,可以将DefaultMessageListenerContainer的日志级别设置为FATAL。

最新更新