All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nofdev.topic.TopicConsumerHandle.groovy Maven / Gradle / Ivy

There is a newer version: 1.7.6
Show newest version
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
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy