org.nofdev.topic.TopicConsumerHandle.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of service-topic-consumer Show documentation
Show all versions of service-topic-consumer Show documentation
The basic componet of Nofdev Topic framework
package org.nofdev.topic
import com.aliyun.mns.model.Message
import groovy.transform.CompileStatic
import org.nofdev.logging.CustomLogger
import java.lang.reflect.Method
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit
/**
* Created by Liutengfei on 2016/5/6 0006.
*/
@CompileStatic
class TopicConsumerHandle extends AbstractTopicConsumerHandle {
private static final CustomLogger logger = CustomLogger.getLogger(TopicConsumerHandle.class)
private TopicConsumerConfig topicConsumerConfig
public TopicConsumerHandle(TopicConsumerConfig config) {
if (!config || !config.getAccessId() || !config.getAccessKey() || !config.getEndpoint() || !config.getGroupId()) {
throw new TopicException("topicProducerConfig中accessId/accessKey/endPoint/groupId是必填项")
}
this.topicConsumerConfig = config
}
void pollMsg(Method method, Object obj, ThreadPoolExecutor executor, TopicConsumerSetting topicConsumerSetting,TopicErrorHandler topicErrorHandler) {
//最初建立连接的时候可能就出错了
def consumer = TopicConsumerContainer.initMNSConsumer(topicConsumerSetting.topicName, this.topicConsumerConfig)
while (true) {
Message popMsg = retry(consumer, 0, topicConsumerSetting)
if (popMsg != null) {
try {
TopicMessage topicMessage = super.getResult(method, popMsg.getMessageBody())
super.onSubmitAsync(obj, topicMessage, method, executor).whenComplete({ Object o, Throwable e ->
if (e) {
logger.error("message handling business exception", e)
topicErrorHandler?.handleError(topicConsumerSetting.topicName,topicMessage,e)
}
def receiptHandle = popMsg.getReceiptHandle()
logger.debug(){"delete message ${receiptHandle}"}
consumer.delete(receiptHandle);
})
while (executor.queue.size() >= topicConsumerSetting.queueSize) {
logger.debug(){"message pull wait"}
sleep(500)
}
} catch (Exception e) {
//框架的错误, 不删除放回, 防止丢失消息
logger.error("message handling exception", e)
}
}
}
}
/**
* 拉取消息的时候可能出现网络暂时性的中断
* @param consumer
* @return
*/
private Message retry(TopicConsumerContainer consumer, int retryCount, TopicConsumerSetting topicConsumerSetting) {
Message popMsg
try {
popMsg = consumer.receive();
} catch (Exception e) {
logger.warn(e){"message [${topicConsumerSetting.topicName}] receive retrying [${retryCount+1}]"}
retryCount = retryStrategy(retryCount, topicConsumerSetting, e)
popMsg = retry(consumer, retryCount, topicConsumerSetting)
}
return popMsg
}
/**
* 2的0次幂到 n 次幂重试, 超出最大次数就会抛出异常
*/
private int retryStrategy(int retryCount, TopicConsumerSetting topicConsumerSetting, Exception e) {
retryCount = retryCount + 1
if (retryCount > topicConsumerSetting.maxRetries) {
logger.error("message handling exception,超出最大重试次数:${topicConsumerSetting.maxRetries}", e)
throw new TopicException("超出最大重试次数", e)
}
TimeUnit.SECONDS.sleep(Math.round(Math.pow(2, retryCount)))
retryCount
}
}