我将Hazelcast用作Tomcat中运行的两个应用程序之间的非持久队列。
问题:QueueListener停止侦听其队列。这意味着,在某个点之前,日志中会定期出现以下行,然后它会消失:
LOGGER.debug("No messages on {}, {}", queueName, QueueListener.this.getClass().getSimpleName());
日志中没有错误。我有几个扩展QueueListener的类,它们都监听一个不同的命名队列。其中一个只是停下来,我不知道为什么,除了一件事:它发生在处理一个项目后。后代类的句柄方法记录了我在日志中可以看到的项目。然后在{queuename}""没有消息记录刚刚消失。执行者有2个线程。两人都停了下来,不确定是否一下子。
后代类的handle方法执行Http请求并记录响应。请注意,在侦听器停止之前,响应未显示在前两个handle
调用的日志中。
后代类的句柄方法没有任何catch块,所以它不会吞下任何异常。 QueueListener中没有记录任何异常。
我的问题,如何找到原因?在哪里寻找它?
将消息发送到此队列的应用程序在与侦听此队列的Tomcat相同的Tomcat中运行。已启用多播(请参阅完整的HazelCast配置)。还有一个运行在同一主机上的其他Tomcat和一些在不同主机上运行的其他Tomcats,它们都连接到同一个Hazelcast实例。他们使用相同的配置。
Hazelcast版本:2.6
QueueListener.java:
package com.mi6.publishers;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class QueueListener<T> {
private static final long TIMEOUT = 10000L;
private static final Logger LOGGER = LoggerFactory.getLogger(QueueListener.class);
/**
* queue which is processed
*/
private IQueue<T> queue;
private final String queueName;
@Autowired
private HazelcastInstance instance;
private ExecutorService svc;
private final int threadCount;
private volatile boolean shutdown = false;
/**
* Constructor
*
* @param queueName
* @param threadCount
*/
public QueueListener(String queueName, int threadCount) {
this.queueName = queueName;
this.threadCount = threadCount;
}
/**
* @PostConstuct Start background threads
*/
@PostConstruct
public void init() {
LOGGER.info("Constructing hazelcast listener for {}", getClass().getSimpleName());
if (instance != null) {
queue = instance.getQueue(queueName);
svc = Executors.newFixedThreadPool(threadCount);
for (int i = 0; i < threadCount; i++) {
svc.submit(new Runnable() {
@Override
public void run() {
while (!shutdown) {
try {
T item = queue.poll(TIMEOUT, TimeUnit.MILLISECONDS);
if (item != null) {
handle(item);
} else {
LOGGER.debug("No messages on {}, {}", queueName, QueueListener.this.getClass().getSimpleName());
}
} catch (InterruptedException ex) {
// do nothing if interrupted
} catch (Exception ex) {
LOGGER.error("Error while receiving messages from queue:{}", queueName);
LOGGER.error("Error while receiving messages", ex);
}
}
}
});
}
} else {
throw new IllegalStateException("Hazelcast instance cannot be null");
}
}
/**
* call before stop
*/
@PreDestroy
public void destroy() {
shutdown = true;
if (svc != null) {
svc.shutdown();
}
}
/**
* Event handler
*
* @param item
*/
public abstract void handle(T item);
public String getQueueName() {
return queueName;
}
}
这是Hazelcast的配置方式:
@Value("${hazelcast.multicast:True}")
private Boolean hazelcastMulticast;
@Value("${hazelcast.group:groupNameNotSet}")
private String hazelcastGroup;
@Bean(destroyMethod = "shutdown")
public HazelcastInstance hazelcastInstance() {
Config cfg = new Config();
cfg.setInstanceName(hazelcastGroup);
NetworkConfig network = cfg.getNetworkConfig();
network.setPortAutoIncrement(true);
Join join = network.getJoin();
join.getMulticastConfig().setEnabled(hazelcastMulticast);
cfg.getGroupConfig().setName(hazelcastGroup);
cfg.getGroupConfig().setPassword(hazelcastGroup);
QueueConfig sms = new QueueConfig();
sms.setName("some-queue-name1");
cfg.addQueueConfig(sms);
QueueConfig flash = new QueueConfig();
flash.setName("some-queue-name2");
cfg.addQueueConfig(flash);
QueueConfig apns = new QueueConfig();
apns.setName("some-queue-name3");
cfg.addQueueConfig(apns);
QueueConfig gcm = new QueueConfig();
gcm.setName("some-queue-name4");
cfg.addQueueConfig(gcm);
return Hazelcast.newHazelcastInstance(cfg);
}