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

com.aliyun.openservices.ons.api.exactlyonce.ExactlyOnceConsumerImpl Maven / Gradle / Ivy

There is a newer version: 1.9.4.Final
Show newest version
package com.aliyun.openservices.ons.api.exactlyonce;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import com.aliyun.openservices.shade.com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import com.aliyun.openservices.shade.com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import com.aliyun.openservices.shade.com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import com.aliyun.openservices.shade.com.alibaba.rocketmq.client.consumer.reporter.ConsumerStatusReporter;
import com.aliyun.openservices.shade.com.alibaba.rocketmq.client.retry.DefaultConsumerRetryStrategy;
import com.aliyun.openservices.shade.com.alibaba.rocketmq.client.retry.RetryStrategy;
import com.aliyun.openservices.shade.com.alibaba.rocketmq.common.UtilAll;
import com.aliyun.openservices.shade.com.alibaba.rocketmq.common.message.MessageExt;

import com.aliyun.openservices.ons.api.Action;
import com.aliyun.openservices.ons.api.ConsumeContext;
import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.MessageListener;
import com.aliyun.openservices.ons.api.MessageSelector;
import com.aliyun.openservices.ons.api.PropertyKeyConst;
import com.aliyun.openservices.ons.api.exactlyonce.aop.model.LocalTxContext;
import com.aliyun.openservices.ons.api.exactlyonce.aop.model.MQTxContext;
import com.aliyun.openservices.ons.api.exactlyonce.aop.proxy.InternalCallback;
import com.aliyun.openservices.ons.api.exactlyonce.aop.proxy.ProxyTxExecuter;
import com.aliyun.openservices.ons.api.exactlyonce.manager.MetricService;
import com.aliyun.openservices.ons.api.exactlyonce.manager.TransactionManager;
import com.aliyun.openservices.ons.api.exactlyonce.manager.util.TxContextUtil;
import com.aliyun.openservices.ons.api.exception.ONSClientException;
import com.aliyun.openservices.ons.api.impl.rocketmq.ONSConsumerAbstract;
import com.aliyun.openservices.ons.api.impl.rocketmq.ONSUtil;

/**
 * @author gongshi
 */
public class ExactlyOnceConsumerImpl extends ONSConsumerAbstract implements ExactlyOnceConsumer {
    private static final String TRUE = "true";
    private final ConcurrentHashMap subscribeTable = new ConcurrentHashMap();
    private boolean exactlyOnceDelivery = false;

    public ExactlyOnceConsumerImpl(final Properties properties) {
        this(properties, new DefaultConsumerRetryStrategy());
    }

    public ExactlyOnceConsumerImpl(final Properties properties, RetryStrategy retryStrategy) {
        super(properties, retryStrategy);
        String suspendTimeMillis = properties.getProperty(PropertyKeyConst.SuspendTimeMillis);
        if (!UtilAll.isBlank(suspendTimeMillis)) {
            try {
                this.defaultMQPushConsumer.setSuspendCurrentQueueTimeMillis(Long.parseLong(suspendTimeMillis));
            } catch (NumberFormatException ignored) {
            }
        }
        this.defaultMQPushConsumer.setConsumerStatusReporter(new ExactlyOnceConsumerStatusReporter());
        this.exactlyOnceDelivery = Boolean.parseBoolean(properties.getProperty(PropertyKeyConst.EXACTLYONCE_DELIVERY, "true"));
        this.exactlyOnceDelivery = this.exactlyOnceDelivery && Boolean.parseBoolean(System.getProperty(PropertyKeyConst.EXACTLYONCE_DELIVERY, TRUE));
        if (this.exactlyOnceDelivery) {
            TransactionManager.start(properties);
        }
    }

    @Override
    public void start() {
        this.defaultMQPushConsumer.registerMessageListener(new MessageConsumerExactlyOnceImpl());
        super.start();
        registerConsumerToManager();
    }

    private void registerConsumerToManager() {
        TransactionManager.addConsumer(this.defaultMQPushConsumer.getConsumerGroup(), this.defaultMQPushConsumer);
    }

    @Override
    public void subscribe(String topic, String subExpression, MessageListener listener) {
        if (null == topic) {
            throw new ONSClientException("topic is null");
        }

        if (null == listener) {
            throw new ONSClientException("listener is null");
        }
        this.subscribeTable.put(topic, listener);
        super.subscribe(topic, subExpression);
    }

    @Override
    public void subscribe(String topic, MessageSelector selector, MessageListener listener) {
        if (null == topic) {
            throw new ONSClientException("topic is null");
        }

        if (null == listener) {
            throw new ONSClientException("listener is null");
        }
        this.subscribeTable.put(topic, listener);
        super.subscribe(topic, selector);
    }

    class MessageConsumerExactlyOnceImpl implements MessageListenerConcurrently {

        @Override
        public ConsumeConcurrentlyStatus consumeMessage(List msglist, final ConsumeConcurrentlyContext consumeConcurrentlyContext) {
            MessageExt msgRMQ = msglist.get(0);
            final String consumerGroup = ExactlyOnceConsumerImpl.this.defaultMQPushConsumer.getConsumerGroup();
            final String internalMsgId = TxContextUtil.buildInternalMsgId(msgRMQ, consumerGroup);
            final Message msg = ONSUtil.msgConvert(msgRMQ);
            msg.setMsgID(msgRMQ.getMsgId());
            final MessageListener listener = ExactlyOnceConsumerImpl.this.subscribeTable.get(msg.getTopic());
            if (null == listener) {
                throw new ONSClientException("MessageListener is null");
            }
            final ConsumeContext context = new ConsumeContext();
            MQTxContext txContext = LocalTxContext.get();
            if (txContext == null) {
                txContext = new MQTxContext();
            }
            txContext.setMessageId(internalMsgId);
            txContext.setConsumerGroup(consumerGroup);
            txContext.setOffset(msgRMQ.getQueueOffset());
            txContext.setTopicName(consumeConcurrentlyContext.getMessageQueue().getTopic());
            txContext.setMessageExt(msgRMQ);
            txContext.setMessageQueue(consumeConcurrentlyContext.getMessageQueue());
            LocalTxContext.set(txContext);
            Action action = null;
            if (ExactlyOnceConsumerImpl.this.exactlyOnceDelivery) {
                action = (Action)ProxyTxExecuter.getInstance().excute(new InternalCallback() {
                    @Override
                    public Object run() {
                        return listener.consume(msg, context);
                    }
                });
            } else {
                action = listener.consume(msg, context);
            }

            MetricService.getInstance().record(txContext);
            consumeConcurrentlyContext.setCheckSendBackHook(new ExactlyOnceCheckSendbackHook(consumerGroup, txContext.getDataSourceConfig()));
            consumeConcurrentlyContext.setExactlyOnceStatus(TxContextUtil.getExactlyOnceStatus(txContext));
            LocalTxContext.clear();

            ConsumeConcurrentlyStatus status = null;
            if (action != null) {
                switch (action) {
                    case CommitMessage:
                        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                    case ReconsumeLater:
                        return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                    default:
                        break;
                }
            }
            return null;
        }
    }

    class ExactlyOnceConsumerStatusReporter implements ConsumerStatusReporter {

        @Override
        public Map reportStatus() {
            return MetricService.getInstance().getCurrentConsumeStatus();
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy