/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.rocketmq.client.impl.producer; import java.io.IOException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.rocketmq.client.QueryResult; import org.apache.rocketmq.client.Validators; import org.apache.rocketmq.client.common.ClientErrorCode; import org.apache.rocketmq.client.exception.MQBrokerException; import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.client.hook.CheckForbiddenContext; import org.apache.rocketmq.client.hook.CheckForbiddenHook; import org.apache.rocketmq.client.hook.SendMessageContext; import org.apache.rocketmq.client.hook.SendMessageHook; import org.apache.rocketmq.client.impl.CommunicationMode; import org.apache.rocketmq.client.impl.MQClientManager; import org.apache.rocketmq.client.impl.factory.MQClientInstance; import org.apache.rocketmq.client.latency.MQFaultStrategy; import org.apache.rocketmq.client.log.ClientLogger; import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.client.producer.LocalTransactionExecuter; import org.apache.rocketmq.client.producer.LocalTransactionState; import org.apache.rocketmq.client.producer.MessageQueueSelector; import org.apache.rocketmq.client.producer.SendCallback; import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.client.producer.SendStatus; import org.apache.rocketmq.client.producer.TransactionCheckListener; import org.apache.rocketmq.client.producer.TransactionListener; import org.apache.rocketmq.client.producer.TransactionMQProducer; import org.apache.rocketmq.client.producer.TransactionSendResult; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.ServiceState; import org.apache.rocketmq.common.UtilAll; import org.apache.rocketmq.common.help.FAQUrl; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageAccessor; import org.apache.rocketmq.common.message.MessageBatch; import org.apache.rocketmq.common.message.MessageClientIDSetter; import org.apache.rocketmq.common.message.MessageConst; import org.apache.rocketmq.common.message.MessageDecoder; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.message.MessageId; import org.apache.rocketmq.common.message.MessageQueue; import org.apache.rocketmq.common.message.MessageType; import org.apache.rocketmq.common.protocol.ResponseCode; import org.apache.rocketmq.common.protocol.header.CheckTransactionStateRequestHeader; import org.apache.rocketmq.common.protocol.header.EndTransactionRequestHeader; import org.apache.rocketmq.common.protocol.header.SendMessageRequestHeader; import org.apache.rocketmq.common.sysflag.MessageSysFlag; import org.apache.rocketmq.logging.InternalLogger; import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.common.RemotingHelper; import org.apache.rocketmq.remoting.exception.RemotingConnectException; import org.apache.rocketmq.remoting.exception.RemotingException; import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException; /** * 默认的Mq生产者实现类 * @author ; */ public class DefaultMQProducerImpl implements MQProducerInner { private final InternalLogger log = ClientLogger.getLog(); /** * 随机数 */ private final Random random = new Random(); /** * 门面 */ private final DefaultMQProducer defaultMQProducer; /** * key: topic,value是topicPublishInfo */ private final ConcurrentMap<String, TopicPublishInfo> topicPublishInfoTable = new ConcurrentHashMap<String, TopicPublishInfo>(); /** * 发送消息的勾子 */ private final ArrayList<SendMessageHook> sendMessageHookList = new ArrayList<SendMessageHook>(); /** * rpc勾子 */ private final RPCHook rpcHook; /** * 阻塞队列 */ protected BlockingQueue<Runnable> checkRequestQueue; /** * 线程池 */ protected ExecutorService checkExecutor; /** * 服务状态 */ private ServiceState serviceState = ServiceState.CREATE_JUST; /** * 客户端实例 */ private MQClientInstance mQClientFactory; /** * checkFibbonHook */ private ArrayList<CheckForbiddenHook> checkForbiddenHookList = new ArrayList<CheckForbiddenHook>(); /** * zip压缩级别 */ private int zipCompressLevel = Integer.parseInt(System.getProperty(MixAll.MESSAGE_COMPRESS_LEVEL, "5")); /** * 消息发送的延迟策略 */ private MQFaultStrategy mqFaultStrategy = new MQFaultStrategy(); public DefaultMQProducerImpl(final DefaultMQProducer defaultMQProducer) { this(defaultMQProducer, null); } public DefaultMQProducerImpl(final DefaultMQProducer defaultMQProducer, RPCHook rpcHook) { this.defaultMQProducer = defaultMQProducer; this.rpcHook = rpcHook; } public void registerCheckForbiddenHook(CheckForbiddenHook checkForbiddenHook) { this.checkForbiddenHookList.add(checkForbiddenHook); log.info("register a new checkForbiddenHook. hookName={}, allHookSize={}", checkForbiddenHook.hookName(), checkForbiddenHookList.size()); } /** * 初始化事务环境 */ public void initTransactionEnv() { TransactionMQProducer producer = (TransactionMQProducer) this.defaultMQProducer; if (producer.getExecutorService() != null) { this.checkExecutor = producer.getExecutorService(); } else { this.checkRequestQueue = new LinkedBlockingQueue<Runnable>(producer.getCheckRequestHoldMax()); this.checkExecutor = new ThreadPoolExecutor( producer.getCheckThreadPoolMinSize(), producer.getCheckThreadPoolMaxSize(), 1000 * 60, TimeUnit.MILLISECONDS, this.checkRequestQueue); } } /** * 销毁事务的环境,其实就是shut 事务回查的线程池 */ public void destroyTransactionEnv() { if (this.checkExecutor != null) { this.checkExecutor.shutdown(); } } public void registerSendMessageHook(final SendMessageHook hook) { this.sendMessageHookList.add(hook); log.info("register sendMessage Hook, {}", hook.hookName()); } /** * 启动生产者 * @throws MQClientException ; */ public void start() throws MQClientException { this.start(true); } /** * 启动生产者 * @param startFactory 是否启动mQClientFactory * @throws MQClientException ; */ public void start(final boolean startFactory) throws MQClientException { switch (this.serviceState) { case CREATE_JUST: this.serviceState = ServiceState.START_FAILED; this.checkConfig(); if (!this.defaultMQProducer.getProducerGroup().equals(MixAll.CLIENT_INNER_PRODUCER_GROUP)) { //更新实例Name变成pid this.defaultMQProducer.changeInstanceNameToPID(); } this.mQClientFactory = MQClientManager.getInstance().getAndCreateMQClientInstance(this.defaultMQProducer, rpcHook); //在mQClientFactory中注册producer boolean registerOK = mQClientFactory.registerProducer(this.defaultMQProducer.getProducerGroup(), this); if (!registerOK) { this.serviceState = ServiceState.CREATE_JUST; throw new MQClientException("The producer group[" + this.defaultMQProducer.getProducerGroup() + "] has been created before, specify another name please." + FAQUrl.suggestTodo(FAQUrl.GROUP_NAME_DUPLICATE_URL), null); } //将创建topic的key放到topicPublishInfoTable,其实就是AUTO_CREATE_TOPIC_KEY_TOPIC this.topicPublishInfoTable.put(this.defaultMQProducer.getCreateTopicKey(), new TopicPublishInfo()); if (startFactory) { //启动 mQClientFactory.start(); } log.info("the producer [{}] start OK. sendMessageWithVIPChannel={}", this.defaultMQProducer.getProducerGroup(), this.defaultMQProducer.isSendMessageWithVIPChannel()); //设置为running状态 this.serviceState = ServiceState.RUNNING; break; case RUNNING: case START_FAILED: case SHUTDOWN_ALREADY: throw new MQClientException("The producer service state not OK, maybe started once, " + this.serviceState + FAQUrl.suggestTodo(FAQUrl.CLIENT_SERVICE_NOT_OK), null); default: break; } this.mQClientFactory.sendHeartbeatToAllBrokerWithLock(); } /** * 检查配置 * @throws MQClientException ; */ private void checkConfig() throws MQClientException { Validators.checkGroup(this.defaultMQProducer.getProducerGroup()); if (null == this.defaultMQProducer.getProducerGroup()) { throw new MQClientException("producerGroup is null", null); } if (this.defaultMQProducer.getProducerGroup().equals(MixAll.DEFAULT_PRODUCER_GROUP)) { throw new MQClientException("producerGroup can not equal " + MixAll.DEFAULT_PRODUCER_GROUP + ", please specify another one.", null); } } public void shutdown() { this.shutdown(true); } public void shutdown(final boolean shutdownFactory) { switch (this.serviceState) { case CREATE_JUST: break; case RUNNING: this.mQClientFactory.unregisterProducer(this.defaultMQProducer.getProducerGroup()); if (shutdownFactory) { this.mQClientFactory.shutdown(); } log.info("the producer [{}] shutdown OK", this.defaultMQProducer.getProducerGroup()); this.serviceState = ServiceState.SHUTDOWN_ALREADY; break; case SHUTDOWN_ALREADY: break; default: break; } } @Override public Set<String> getPublishTopicList() { Set<String> topicList = new HashSet<String>(); for (String key : this.topicPublishInfoTable.keySet()) { topicList.add(key); } return topicList; } /** * topicPublishInfo是否需要更新 * @param topic topic topic * @return ; */ @Override public boolean isPublishTopicNeedUpdate(String topic) { TopicPublishInfo prev = this.topicPublishInfoTable.get(topic); return null == prev || !prev.ok(); } /** * This method will be removed in the version 5.0.0 and <code>getCheckListener</code> is recommended. * @return */ @Override @Deprecated public TransactionCheckListener checkListener() { if (this.defaultMQProducer instanceof TransactionMQProducer) { TransactionMQProducer producer = (TransactionMQProducer) defaultMQProducer; return producer.getTransactionCheckListener(); } return null; } /** * 获取事务回查checklistener * @return ; */ @Override public TransactionListener getCheckListener() { if (this.defaultMQProducer instanceof TransactionMQProducer) { TransactionMQProducer producer = (TransactionMQProducer) defaultMQProducer; return producer.getTransactionListener(); } return null; } /** * 进行事务回查逻辑处理 * @param addr server地址 * @param msg msg * @param header header */ @Override public void checkTransactionState(final String addr, final MessageExt msg, final CheckTransactionStateRequestHeader header) { Runnable request = new Runnable() { private final String brokerAddr = addr; private final MessageExt message = msg; private final CheckTransactionStateRequestHeader checkRequestHeader = header; private final String group = DefaultMQProducerImpl.this.defaultMQProducer.getProducerGroup(); @Override public void run() { TransactionCheckListener transactionCheckListener = DefaultMQProducerImpl.this.checkListener(); TransactionListener transactionListener = getCheckListener(); if (transactionCheckListener != null || transactionListener != null) { LocalTransactionState localTransactionState = LocalTransactionState.UNKNOW; Throwable exception = null; try { if (transactionCheckListener != null) { localTransactionState = transactionCheckListener.checkLocalTransactionState(message); } else if (transactionListener != null) { log.debug("Used new check API in transaction message"); localTransactionState = transactionListener.checkLocalTransaction(message); } else { log.warn("CheckTransactionState, pick transactionListener by group[{}] failed", group); } } catch (Throwable e) { log.error("Broker call checkTransactionState, but checkLocalTransactionState exception", e); exception = e; } this.processTransactionState( localTransactionState, group, exception); } else { log.warn("CheckTransactionState, pick transactionCheckListener by group[{}] failed", group); } } /** * 处理事务回查的状态结果 * @param localTransactionState 事务状态 * @param producerGroup 生产者group * @param exception 异常 */ private void processTransactionState( final LocalTransactionState localTransactionState, final String producerGroup, final Throwable exception) { final EndTransactionRequestHeader thisHeader = new EndTransactionRequestHeader(); thisHeader.setCommitLogOffset(checkRequestHeader.getCommitLogOffset()); thisHeader.setProducerGroup(producerGroup); thisHeader.setTranStateTableOffset(checkRequestHeader.getTranStateTableOffset()); thisHeader.setFromTransactionCheck(true); String uniqueKey = message.getProperties().get(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); if (uniqueKey == null) { uniqueKey = message.getMsgId(); } thisHeader.setMsgId(uniqueKey); thisHeader.setTransactionId(checkRequestHeader.getTransactionId()); switch (localTransactionState) { case COMMIT_MESSAGE: thisHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_COMMIT_TYPE); break; case ROLLBACK_MESSAGE: thisHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_ROLLBACK_TYPE); log.warn("when broker check, client rollback this transaction, {}", thisHeader); break; case UNKNOW: thisHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_NOT_TYPE); log.warn("when broker check, client does not know this transaction state, {}", thisHeader); break; default: break; } String remark = null; if (exception != null) { remark = "checkLocalTransactionState Exception: " + RemotingHelper.exceptionSimpleDesc(exception); } try { DefaultMQProducerImpl.this.mQClientFactory.getMQClientAPIImpl().endTransactionOneway(brokerAddr, thisHeader, remark, 3000); } catch (Exception e) { log.error("endTransactionOneway exception", e); } } }; //在回查线程池执行该request this.checkExecutor.submit(request); } /** * 更新topicPublishInfotable * @param topic ; * @param info ; */ @Override public void updateTopicPublishInfo(final String topic, final TopicPublishInfo info) { if (info != null && topic != null) { TopicPublishInfo prev = this.topicPublishInfoTable.put(topic, info); if (prev != null) { log.info("updateTopicPublishInfo prev is not null, " + prev.toString()); } } } @Override public boolean isUnitMode() { return this.defaultMQProducer.isUnitMode(); } /** * 创建topic * @param key key * @param newTopic newtopic * @param queueNum 队列数 * @throws MQClientException ; */ public void createTopic(String key, String newTopic, int queueNum) throws MQClientException { createTopic(key, newTopic, queueNum, 0); } /** * 创建topic * @param key key topic * @param newTopic topic * @param queueNum 队列数 * @param topicSysFlag flag * @throws MQClientException ; */ public void createTopic(String key, String newTopic, int queueNum, int topicSysFlag) throws MQClientException { this.makeSureStateOK(); Validators.checkTopic(newTopic); this.mQClientFactory.getMQAdminImpl().createTopic(key, newTopic, queueNum, topicSysFlag); } /** * 确保是running状态 * @throws MQClientException ; */ private void makeSureStateOK() throws MQClientException { if (this.serviceState != ServiceState.RUNNING) { throw new MQClientException("The producer service state not OK, " + this.serviceState + FAQUrl.suggestTodo(FAQUrl.CLIENT_SERVICE_NOT_OK), null); } } /** * 根据topic获取队列信息 * @param topic ; * @return ; * @throws MQClientException ; */ public List<MessageQueue> fetchPublishMessageQueues(String topic) throws MQClientException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().fetchPublishMessageQueues(topic); } /** * 查询队列的偏移量 * @param mq mq * @param timestamp 时间戳 * @return ; * @throws MQClientException ; */ public long searchOffset(MessageQueue mq, long timestamp) throws MQClientException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().searchOffset(mq, timestamp); } /** * 查询一个队列的最大偏移量 * @param mq mq * @return ; * @throws MQClientException ; */ public long maxOffset(MessageQueue mq) throws MQClientException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().maxOffset(mq); } /** * 查询一个队列的最小的偏移哦 * @param mq mq * @return ; * @throws MQClientException ; */ public long minOffset(MessageQueue mq) throws MQClientException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().minOffset(mq); } /** * 查询消息最早的存储时间 * @param mq ; * @return ; * @throws MQClientException ; */ public long earliestMsgStoreTime(MessageQueue mq) throws MQClientException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().earliestMsgStoreTime(mq); } /** * 根据msgid查询消息 * @param msgId ; * @return ; * @throws RemotingException ; * @throws MQBrokerException ; * @throws InterruptedException ; * @throws MQClientException ; */ public MessageExt viewMessage( String msgId) throws RemotingException, MQBrokerException, InterruptedException, MQClientException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().viewMessage(msgId); } /** * 根据范围查询消息 */ public QueryResult queryMessage(String topic, String key, int maxNum, long begin, long end) throws MQClientException, InterruptedException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().queryMessage(topic, key, maxNum, begin, end); } /** * 根据uniqKe查询消息 * @param topic topic * @param uniqKey uniqkey * @return ; * @throws MQClientException ; * @throws InterruptedException ; */ public MessageExt queryMessageByUniqKey(String topic, String uniqKey) throws MQClientException, InterruptedException { this.makeSureStateOK(); return this.mQClientFactory.getMQAdminImpl().queryMessageByUniqKey(topic, uniqKey); } /** * DEFAULT ASYNC ------------------------------------------------------- * 默认的异步发送消息 */ public void send(Message msg, SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException { send(msg, sendCallback, this.defaultMQProducer.getSendMsgTimeout()); } /** * 带超时时间的异步发送 * It will be removed at 4.4.0 cause for exception handling and the wrong Semantics of timeout. * A new one will be provided in next version * @param msg ; * @param sendCallback ; * @param timeout the <code>sendCallback</code> will be invoked at most time * @throws RejectedExecutionException ; */ @Deprecated public void send(final Message msg, final SendCallback sendCallback, final long timeout) throws MQClientException, RemotingException, InterruptedException { final long beginStartTime = System.currentTimeMillis(); //异步线程池 ExecutorService executor = this.getCallbackExecutor(); try { executor.submit(new Runnable() { @Override public void run() { long costTime = System.currentTimeMillis() - beginStartTime; if (timeout > costTime) { try { sendDefaultImpl(msg, CommunicationMode.ASYNC, sendCallback, timeout - costTime); } catch (Exception e) { sendCallback.onException(e); } } else { sendCallback.onException( new RemotingTooMuchRequestException("DEFAULT ASYNC send call timeout")); } } }); } catch (RejectedExecutionException e) { throw new MQClientException("executor rejected ", e); } } /** * 选择一个队列发送message * @param tpInfo tpinfo * @param lastBrokerName lastbrokerName * @return ; */ public MessageQueue selectOneMessageQueue(final TopicPublishInfo tpInfo, final String lastBrokerName) { return this.mqFaultStrategy.selectOneMessageQueue(tpInfo, lastBrokerName); } /** * 更新brokerName的延迟时间统计 * @param brokerName ; * @param currentLatency ; * @param isolation ; */ public void updateFaultItem(final String brokerName, final long currentLatency, boolean isolation) { this.mqFaultStrategy.updateFaultItem(brokerName, currentLatency, isolation); } /** * 默认的发送消息实现类 * @param msg msg * @param communicationMode 发送模式 * @param sendCallback callback * @param timeout 超时 * @return SendResult * @throws MQClientException ; * @throws RemotingException ; * @throws MQBrokerException ; * @throws InterruptedException ; */ private SendResult sendDefaultImpl( Message msg, final CommunicationMode communicationMode, final SendCallback sendCallback, final long timeout ) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { this.makeSureStateOK(); Validators.checkMessage(msg, this.defaultMQProducer); //执行id final long invokeID = random.nextLong(); //开始时间戳 long beginTimestampFirst = System.currentTimeMillis(); //上一个时间戳 long beginTimestampPrev = beginTimestampFirst; //end时间戳 long endTimestamp = beginTimestampFirst; //尝试找到TopicPublishInfo TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic()); if (topicPublishInfo != null && topicPublishInfo.ok()) { //调用是否超时了 boolean callTimeout = false; //选择的队列 MessageQueue mq = null; //异常 Exception exception = null; //发送结果 SendResult sendResult = null; //重试次数配置,同步为 1+ this.defaultMQProducer.getRetryTimesWhenSendFailed() ,异步为1 int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1; //发送次数 int times = 0; //历次选取的broker名称 String[] brokersSent = new String[timesTotal]; for (; times < timesTotal; times++) { //上一个brokerName,一开始为null String lastBrokerName = null == mq ? null : mq.getBrokerName(); MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, lastBrokerName); if (mqSelected != null) { mq = mqSelected; brokersSent[times] = mq.getBrokerName(); try { //是否超时了 beginTimestampPrev = System.currentTimeMillis(); long costTime = beginTimestampPrev - beginTimestampFirst; if (timeout < costTime) { callTimeout = true; break; } //执行同步调用 sendResult = this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout - costTime); endTimestamp = System.currentTimeMillis(); //更新broker的延迟统计 this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false); switch (communicationMode) { case ASYNC: return null; case ONEWAY: return null; case SYNC: //如果没有sendOK,并且retryAnotherBrokerWhenNotStoreOK 为true,就continue if (sendResult.getSendStatus() != SendStatus.SEND_OK) { if (this.defaultMQProducer.isRetryAnotherBrokerWhenNotStoreOK()) { continue; } } //否则发送结果直接返回 return sendResult; default: break; } } catch (RemotingException e) { endTimestamp = System.currentTimeMillis(); //发送异常,更新broker的延迟统计 this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true); log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e); log.warn(msg.toString()); exception = e; continue; } catch (MQClientException e) { endTimestamp = System.currentTimeMillis(); //发送异常,更新broker的延迟统计 this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true); log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e); log.warn(msg.toString()); exception = e; continue; } catch (MQBrokerException e) { endTimestamp = System.currentTimeMillis(); //发送异常,更新broker的延迟统计 this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, true); log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e); log.warn(msg.toString()); exception = e; switch (e.getResponseCode()) { case ResponseCode.TOPIC_NOT_EXIST: case ResponseCode.SERVICE_NOT_AVAILABLE: case ResponseCode.SYSTEM_ERROR: case ResponseCode.NO_PERMISSION: case ResponseCode.NO_BUYER_ID: case ResponseCode.NOT_IN_CURRENT_UNIT: continue; default: if (sendResult != null) { return sendResult; } throw e; } } catch (InterruptedException e) { endTimestamp = System.currentTimeMillis(); //发送异常,更新broker的延迟统计 this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false); log.warn(String.format("sendKernelImpl exception, throw exception, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mq), e); log.warn(msg.toString()); log.warn("sendKernelImpl exception", e); log.warn(msg.toString()); throw e; } } else { break; } } //如果发送结果不为空,就返回 if (sendResult != null) { return sendResult; } //发送多次,仍然失败。 String info = String.format("Send [%d] times, still failed, cost [%d]ms, Topic: %s, BrokersSent: %s", times, System.currentTimeMillis() - beginTimestampFirst, msg.getTopic(), Arrays.toString(brokersSent)); info += FAQUrl.suggestTodo(FAQUrl.SEND_MSG_FAILED); MQClientException mqClientException = new MQClientException(info, exception); //超时,就抛出了超时的异常 if (callTimeout) { throw new RemotingTooMuchRequestException("sendDefaultImpl call timeout"); } //分门别类对应responseCode if (exception instanceof MQBrokerException) { mqClientException.setResponseCode(((MQBrokerException) exception).getResponseCode()); } else if (exception instanceof RemotingConnectException) { mqClientException.setResponseCode(ClientErrorCode.CONNECT_BROKER_EXCEPTION); } else if (exception instanceof RemotingTimeoutException) { mqClientException.setResponseCode(ClientErrorCode.ACCESS_BROKER_TIMEOUT); } else if (exception instanceof MQClientException) { mqClientException.setResponseCode(ClientErrorCode.BROKER_NOT_EXIST_EXCEPTION); } throw mqClientException; } /* * 抛出错误,比如nameServer不存在或者No route info of this topic */ List<String> nsList = this.getmQClientFactory().getMQClientAPIImpl().getNameServerAddressList(); if (null == nsList || nsList.isEmpty()) { throw new MQClientException( "No name server address, please set it." + FAQUrl.suggestTodo(FAQUrl.NAME_SERVER_ADDR_NOT_EXIST_URL), null).setResponseCode(ClientErrorCode.NO_NAME_SERVER_EXCEPTION); } throw new MQClientException("No route info of this topic, " + msg.getTopic() + FAQUrl.suggestTodo(FAQUrl.NO_TOPIC_ROUTE_INFO), null).setResponseCode(ClientErrorCode.NOT_FOUND_TOPIC_EXCEPTION); } /** * 尝试根据topic找到TopicPublishInfo * @param topic topic * @return ; */ private TopicPublishInfo tryToFindTopicPublishInfo(final String topic) { TopicPublishInfo topicPublishInfo = this.topicPublishInfoTable.get(topic); if (null == topicPublishInfo || !topicPublishInfo.ok()) { this.topicPublishInfoTable.putIfAbsent(topic, new TopicPublishInfo()); this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic); topicPublishInfo = this.topicPublishInfoTable.get(topic); } //如果ok就返回 if (topicPublishInfo.isHaveTopicRouterInfo() || topicPublishInfo.ok()) { return topicPublishInfo; } else { //没有就第一次创建 this.mQClientFactory.updateTopicRouteInfoFromNameServer(topic, true, this.defaultMQProducer); topicPublishInfo = this.topicPublishInfoTable.get(topic); return topicPublishInfo; } } /** * 真正的发送消息。执行与broker的调用 * @param msg 消息 * @param mq 队列 * @param communicationMode 发送模式 * @param sendCallback 异步发送的话,回调勾子 * @param topicPublishInfo topic发布详情 * @param timeout 超时时间 * @return {@link SendResult} * @throws MQClientException ; * @throws RemotingException ; * @throws MQBrokerException ; * @throws InterruptedException ; */ private SendResult sendKernelImpl(final Message msg, final MessageQueue mq, final CommunicationMode communicationMode, final SendCallback sendCallback, final TopicPublishInfo topicPublishInfo, final long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { //开始时间 long beginStartTime = System.currentTimeMillis(); //找到broker的master地址 String brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(mq.getBrokerName()); //如果broker的Addr地址为空,会再去nameServer寻找路由 if (null == brokerAddr) { tryToFindTopicPublishInfo(mq.getTopic()); brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(mq.getBrokerName()); } SendMessageContext context = null; if (brokerAddr != null) { //找到vip的地址 brokerAddr = MixAll.brokerVIPChannel(this.defaultMQProducer.isSendMessageWithVIPChannel(), brokerAddr); byte[] prevBody = msg.getBody(); try { //for MessageBatch,ID has been set in the generating process if (!(msg instanceof MessageBatch)) { // MessageClientIDSetter.setUniqID(msg); } int sysFlag = 0; boolean msgBodyCompressed = false; if (this.tryToCompressMessage(msg)) { //设置压缩标记 sysFlag |= MessageSysFlag.COMPRESSED_FLAG; msgBodyCompressed = true; } //如果是prepare事务消息,标记事务消息的flag final String tranMsg = msg.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); if (tranMsg != null && Boolean.parseBoolean(tranMsg)) { sysFlag |= MessageSysFlag.TRANSACTION_PREPARED_TYPE; } //检查forbiddenHook执行 if (hasCheckForbiddenHook()) { CheckForbiddenContext checkForbiddenContext = new CheckForbiddenContext(); checkForbiddenContext.setNameSrvAddr(this.defaultMQProducer.getNamesrvAddr()); checkForbiddenContext.setGroup(this.defaultMQProducer.getProducerGroup()); checkForbiddenContext.setCommunicationMode(communicationMode); checkForbiddenContext.setBrokerAddr(brokerAddr); checkForbiddenContext.setMessage(msg); checkForbiddenContext.setMq(mq); checkForbiddenContext.setUnitMode(this.isUnitMode()); this.executeCheckForbiddenHook(checkForbiddenContext); } /* * 如果有sendMessageHook,就依次执行sendHessageHook */ if (this.hasSendMessageHook()) { context = new SendMessageContext(); context.setProducer(this); context.setProducerGroup(this.defaultMQProducer.getProducerGroup()); context.setCommunicationMode(communicationMode); context.setBornHost(this.defaultMQProducer.getClientIP()); context.setBrokerAddr(brokerAddr); context.setMessage(msg); context.setMq(mq); String isTrans = msg.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED); if (isTrans != null && isTrans.equals("true")) { //设置为halfMessage context.setMsgType(MessageType.Trans_Msg_Half); } //设置延迟消息的标记 if (msg.getProperty("__STARTDELIVERTIME") != null || msg.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null) { context.setMsgType(MessageType.Delay_Msg); } this.executeSendMessageHookBefore(context); } /* * 发送消息的请求header */ SendMessageRequestHeader requestHeader = new SendMessageRequestHeader(); requestHeader.setProducerGroup(this.defaultMQProducer.getProducerGroup()); requestHeader.setTopic(msg.getTopic()); requestHeader.setDefaultTopic(this.defaultMQProducer.getCreateTopicKey()); requestHeader.setDefaultTopicQueueNums(this.defaultMQProducer.getDefaultTopicQueueNums()); requestHeader.setQueueId(mq.getQueueId()); requestHeader.setSysFlag(sysFlag); requestHeader.setBornTimestamp(System.currentTimeMillis()); requestHeader.setFlag(msg.getFlag()); requestHeader.setProperties(MessageDecoder.messageProperties2String(msg.getProperties())); requestHeader.setReconsumeTimes(0); requestHeader.setUnitMode(this.isUnitMode()); requestHeader.setBatch(msg instanceof MessageBatch); //如果topic是%RETRY%,对重试消息特殊处理 if (requestHeader.getTopic().startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) { String reconsumeTimes = MessageAccessor.getReconsumeTime(msg); if (reconsumeTimes != null) { requestHeader.setReconsumeTimes(Integer.valueOf(reconsumeTimes)); MessageAccessor.clearProperty(msg, MessageConst.PROPERTY_RECONSUME_TIME); } String maxReconsumeTimes = MessageAccessor.getMaxReconsumeTimes(msg); if (maxReconsumeTimes != null) { requestHeader.setMaxReconsumeTimes(Integer.valueOf(maxReconsumeTimes)); MessageAccessor.clearProperty(msg, MessageConst.PROPERTY_MAX_RECONSUME_TIMES); } } SendResult sendResult = null; switch (communicationMode) { case ASYNC: //异步消息,temMessage Message tmpMessage = msg; //如果消息体压缩 if (msgBodyCompressed) { //If msg body was compressed, msgbody should be reset using prevBody. //Clone new message using commpressed message body and recover origin massage. //Fix bug:https://github.com/apache/rocketmq-externals/issues/66 tmpMessage = MessageAccessor.cloneMessage(msg); msg.setBody(prevBody); } //超时 long costTimeAsync = System.currentTimeMillis() - beginStartTime; if (timeout < costTimeAsync) { throw new RemotingTooMuchRequestException("sendKernelImpl call timeout"); } //发送Message sendResult = this.mQClientFactory.getMQClientAPIImpl().sendMessage( brokerAddr, mq.getBrokerName(), tmpMessage, requestHeader, timeout - costTimeAsync, communicationMode, sendCallback, topicPublishInfo, this.mQClientFactory, this.defaultMQProducer.getRetryTimesWhenSendAsyncFailed(), context, this); break; //同步和oneway case ONEWAY: case SYNC: long costTimeSync = System.currentTimeMillis() - beginStartTime; if (timeout < costTimeSync) { throw new RemotingTooMuchRequestException("sendKernelImpl call timeout"); } //真正调用getMQClientAPIImpl发送消息 sendResult = this.mQClientFactory.getMQClientAPIImpl().sendMessage( brokerAddr, mq.getBrokerName(), msg, requestHeader, timeout - costTimeSync, communicationMode, context, this); break; default: assert false; break; } //执行勾子 if (this.hasSendMessageHook()) { context.setSendResult(sendResult); this.executeSendMessageHookAfter(context); } return sendResult; //下面都是处理各种异常,勾子 } catch (RemotingException e) { if (this.hasSendMessageHook()) { context.setException(e); this.executeSendMessageHookAfter(context); } throw e; } catch (MQBrokerException e) { if (this.hasSendMessageHook()) { context.setException(e); this.executeSendMessageHookAfter(context); } throw e; } catch (InterruptedException e) { if (this.hasSendMessageHook()) { context.setException(e); this.executeSendMessageHookAfter(context); } throw e; } finally { msg.setBody(prevBody); } } //broker不存在 throw new MQClientException("The broker[" + mq.getBrokerName() + "] not exist", null); } public MQClientInstance getmQClientFactory() { return mQClientFactory; } /** * 尝试来压缩Message * @param msg msg * @return ; */ private boolean tryToCompressMessage(final Message msg) { //批量消息不支持压缩 if (msg instanceof MessageBatch) { //batch dose not support compressing right now return false; } byte[] body = msg.getBody(); if (body != null) { //如果消息大于4kb就要压缩 if (body.length >= this.defaultMQProducer.getCompressMsgBodyOverHowmuch()) { try { byte[] data = UtilAll.compress(body, zipCompressLevel); if (data != null) { msg.setBody(data); return true; } } catch (IOException e) { log.error("tryToCompressMessage exception", e); log.warn(msg.toString()); } } } return false; } /** * 下面2个方法,执行并检查checkforbiddonhook */ public boolean hasCheckForbiddenHook() { return !checkForbiddenHookList.isEmpty(); } public void executeCheckForbiddenHook(final CheckForbiddenContext context) throws MQClientException { if (hasCheckForbiddenHook()) { for (CheckForbiddenHook hook : checkForbiddenHookList) { hook.checkForbidden(context); } } } /** * 检查并依次执行sendMessageHook..执行失败,不能影响发送消息的主流程 * @return ; */ public boolean hasSendMessageHook() { return !this.sendMessageHookList.isEmpty(); } public void executeSendMessageHookBefore(final SendMessageContext context) { if (!this.sendMessageHookList.isEmpty()) { for (SendMessageHook hook : this.sendMessageHookList) { try { hook.sendMessageBefore(context); } catch (Throwable e) { log.warn("failed to executeSendMessageHookBefore", e); } } } } /** * 执行sendMessageHookAfter * @param context ; */ public void executeSendMessageHookAfter(final SendMessageContext context) { if (!this.sendMessageHookList.isEmpty()) { for (SendMessageHook hook : this.sendMessageHookList) { try { hook.sendMessageAfter(context); } catch (Throwable e) { log.warn("failed to executeSendMessageHookAfter", e); } } } } /** * DEFAULT ONEWAY ------------------------------------------------------- * 默认的oneWay发送 */ public void sendOneway(Message msg) throws MQClientException, RemotingException, InterruptedException { try { this.sendDefaultImpl(msg, CommunicationMode.ONEWAY, null, this.defaultMQProducer.getSendMsgTimeout()); } catch (MQBrokerException e) { throw new MQClientException("unknown exception", e); } } /** * KERNEL SYNC ------------------------------------------------------- * 专门选取某个队列同步发送 */ public SendResult send(Message msg, MessageQueue mq) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return send(msg, mq, this.defaultMQProducer.getSendMsgTimeout()); } /** * 专门选取某一个队列同步发送 * @param msg msg * @param mq mq * @param timeout timeout * @return ; * @throws MQClientException ; * @throws RemotingException ; * @throws MQBrokerException ; * @throws InterruptedException ; */ public SendResult send(Message msg, MessageQueue mq, long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { long beginStartTime = System.currentTimeMillis(); this.makeSureStateOK(); Validators.checkMessage(msg, this.defaultMQProducer); if (!msg.getTopic().equals(mq.getTopic())) { throw new MQClientException("message's topic not equal mq's topic", null); } long costTime = System.currentTimeMillis() - beginStartTime; if (timeout < costTime) { throw new RemotingTooMuchRequestException("call timeout"); } return this.sendKernelImpl(msg, mq, CommunicationMode.SYNC, null, null, timeout); } /** * KERNEL ASYNC ------------------------------------------------------- * 专门选取一个队列发送异步消息 */ public void send(Message msg, MessageQueue mq, SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException { send(msg, mq, sendCallback, this.defaultMQProducer.getSendMsgTimeout()); } /** * It will be removed at 4.4.0 cause for exception handling and the wrong Semantics of timeout. * A new one will be provided in next version * 专门选取一个队列发送异步消息,带超时时间 * @param msg ; * @param mq ; * @param sendCallback ; * @param timeout the <code>sendCallback</code> will be invoked at most time * @throws MQClientException ; * @throws RemotingException ; * @throws InterruptedException ; */ @Deprecated public void send(final Message msg, final MessageQueue mq, final SendCallback sendCallback, final long timeout) throws MQClientException, RemotingException, InterruptedException { final long beginStartTime = System.currentTimeMillis(); ExecutorService executor = this.getCallbackExecutor(); try { executor.submit(new Runnable() { @Override public void run() { try { makeSureStateOK(); Validators.checkMessage(msg, defaultMQProducer); if (!msg.getTopic().equals(mq.getTopic())) { throw new MQClientException("message's topic not equal mq's topic", null); } long costTime = System.currentTimeMillis() - beginStartTime; if (timeout > costTime) { try { sendKernelImpl(msg, mq, CommunicationMode.ASYNC, sendCallback, null, timeout - costTime); } catch (MQBrokerException e) { throw new MQClientException("unknown exception", e); } } else { sendCallback.onException(new RemotingTooMuchRequestException("call timeout")); } } catch (Exception e) { sendCallback.onException(e); } } }); } catch (RejectedExecutionException e) { throw new MQClientException("executor rejected ", e); } } /** * KERNEL ONEWAY ------------------------------------------------------- * 专门选取一个队列sendOneway */ public void sendOneway(Message msg, MessageQueue mq) throws MQClientException, RemotingException, InterruptedException { this.makeSureStateOK(); Validators.checkMessage(msg, this.defaultMQProducer); try { this.sendKernelImpl(msg, mq, CommunicationMode.ONEWAY, null, null, this.defaultMQProducer.getSendMsgTimeout()); } catch (MQBrokerException e) { throw new MQClientException("unknown exception", e); } } /** * SELECT SYNC ------------------------------------------------------- * 同步发送,带队列选择器。一般是顺序消息会使用 * */ public SendResult send(Message msg, MessageQueueSelector selector, Object arg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return send(msg, selector, arg, this.defaultMQProducer.getSendMsgTimeout()); } /** * 同步发送,带队列选择器 * @param msg msg * @param selector 队列选择器 * @param arg args * @param timeout 超时 * @return ; * @throws MQClientException ; * @throws RemotingException ; * @throws MQBrokerException ; * @throws InterruptedException ; */ public SendResult send(Message msg, MessageQueueSelector selector, Object arg, long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return this.sendSelectImpl(msg, selector, arg, CommunicationMode.SYNC, null, timeout); } /** * 带队列选择器的发送 * @param msg msg * @param selector selector * @param arg arg * @param communicationMode 发送模型 * @param sendCallback callback * @param timeout timeout * @return ; * @throws MQClientException ; * @throws RemotingException ; * @throws MQBrokerException ; * @throws InterruptedException ; */ private SendResult sendSelectImpl( Message msg, MessageQueueSelector selector, Object arg, final CommunicationMode communicationMode, final SendCallback sendCallback, final long timeout ) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { long beginStartTime = System.currentTimeMillis(); this.makeSureStateOK(); Validators.checkMessage(msg, this.defaultMQProducer); TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic()); if (topicPublishInfo != null && topicPublishInfo.ok()) { MessageQueue mq = null; try { mq = selector.select(topicPublishInfo.getMessageQueueList(), msg, arg); } catch (Throwable e) { throw new MQClientException("select message queue throwed exception.", e); } long costTime = System.currentTimeMillis() - beginStartTime; if (timeout < costTime) { throw new RemotingTooMuchRequestException("sendSelectImpl call timeout"); } if (mq != null) { return this.sendKernelImpl(msg, mq, communicationMode, sendCallback, null, timeout - costTime); } else { throw new MQClientException("select message queue return null.", null); } } throw new MQClientException("No route info for this topic, " + msg.getTopic(), null); } /** * SELECT ASYNC ------------------------------------------------------ * 异步的,带队列选择器的发送 */ public void send(Message msg, MessageQueueSelector selector, Object arg, SendCallback sendCallback) throws MQClientException, RemotingException, InterruptedException { send(msg, selector, arg, sendCallback, this.defaultMQProducer.getSendMsgTimeout()); } /** * It will be removed at 4.4.0 cause for exception handling and the wrong Semantics of timeout. * A new one will be provided in next version * 异步的,带队列选择器的发送,包含超时时间 * @param msg ; * @param selector ; * @param arg ; * @param sendCallback ; * @param timeout the <code>sendCallback</code> will be invoked at most time * @throws MQClientException ; * @throws RemotingException ; * @throws InterruptedException ; */ @Deprecated public void send(final Message msg, final MessageQueueSelector selector, final Object arg, final SendCallback sendCallback, final long timeout) throws MQClientException, RemotingException, InterruptedException { final long beginStartTime = System.currentTimeMillis(); ExecutorService executor = this.getCallbackExecutor(); try { executor.submit(new Runnable() { @Override public void run() { long costTime = System.currentTimeMillis() - beginStartTime; if (timeout > costTime) { try { try { sendSelectImpl(msg, selector, arg, CommunicationMode.ASYNC, sendCallback, timeout - costTime); } catch (MQBrokerException e) { throw new MQClientException("unknownn exception", e); } } catch (Exception e) { sendCallback.onException(e); } } else { sendCallback.onException(new RemotingTooMuchRequestException("call timeout")); } } }); } catch (RejectedExecutionException e) { throw new MQClientException("exector rejected ", e); } } /** * SELECT ONEWAY ------------------------------------------------------- * oneWay。单队列选择器 */ public void sendOneway(Message msg, MessageQueueSelector selector, Object arg) throws MQClientException, RemotingException, InterruptedException { try { this.sendSelectImpl(msg, selector, arg, CommunicationMode.ONEWAY, null, this.defaultMQProducer.getSendMsgTimeout()); } catch (MQBrokerException e) { throw new MQClientException("unknown exception", e); } } /** * 发送prepare的事务消息半消息 * @param msg 消息 * @param localTransactionExecuter 本地事务执行器 * @param arg arg * @return ; * @throws MQClientException ; */ public TransactionSendResult sendMessageInTransaction(final Message msg, final LocalTransactionExecuter localTransactionExecuter, final Object arg) throws MQClientException { TransactionListener transactionListener = getCheckListener(); if (null == localTransactionExecuter && null == transactionListener) { throw new MQClientException("tranExecutor is null", null); } Validators.checkMessage(msg, this.defaultMQProducer); SendResult sendResult = null; //添加事务消息的标识 MessageAccessor.putProperty(msg, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true"); MessageAccessor.putProperty(msg, MessageConst.PROPERTY_PRODUCER_GROUP, this.defaultMQProducer.getProducerGroup()); try { sendResult = this.send(msg); } catch (Exception e) { throw new MQClientException("send message Exception", e); } LocalTransactionState localTransactionState = LocalTransactionState.UNKNOW; Throwable localException = null; switch (sendResult.getSendStatus()) { case SEND_OK: { try { if (sendResult.getTransactionId() != null) { //添加事务id msg.putUserProperty("__transactionId__", sendResult.getTransactionId()); } //unidkey String transactionId = msg.getProperty(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX); if (null != transactionId && !"".equals(transactionId)) { msg.setTransactionId(transactionId); } //新老版本兼容处理,执行本地事务 if (null != localTransactionExecuter) { localTransactionState = localTransactionExecuter.executeLocalTransactionBranch(msg, arg); } else if (transactionListener != null) { log.debug("Used new transaction API"); localTransactionState = transactionListener.executeLocalTransaction(msg, arg); } //未知状态 if (null == localTransactionState) { localTransactionState = LocalTransactionState.UNKNOW; } if (localTransactionState != LocalTransactionState.COMMIT_MESSAGE) { log.info("executeLocalTransactionBranch return {}", localTransactionState); log.info(msg.toString()); } } catch (Throwable e) { log.info("executeLocalTransactionBranch exception", e); log.info(msg.toString()); localException = e; } } break; case FLUSH_DISK_TIMEOUT: case FLUSH_SLAVE_TIMEOUT: case SLAVE_NOT_AVAILABLE: localTransactionState = LocalTransactionState.ROLLBACK_MESSAGE; break; default: break; } try { this.endTransaction(sendResult, localTransactionState, localException); } catch (Exception e) { log.warn("local transaction execute " + localTransactionState + ", but end broker transaction failed", e); } TransactionSendResult transactionSendResult = new TransactionSendResult(); transactionSendResult.setSendStatus(sendResult.getSendStatus()); transactionSendResult.setMessageQueue(sendResult.getMessageQueue()); transactionSendResult.setMsgId(sendResult.getMsgId()); transactionSendResult.setQueueOffset(sendResult.getQueueOffset()); transactionSendResult.setTransactionId(sendResult.getTransactionId()); transactionSendResult.setLocalTransactionState(localTransactionState); return transactionSendResult; } /** * DEFAULT SYNC ------------------------------------------------------- * 发送消息 */ public SendResult send( Message msg) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return send(msg, this.defaultMQProducer.getSendMsgTimeout()); } /** * premare事务发送结果处理 * @param sendResult 发送结果 * @param localTransactionState 本地状态 * @param localException 异常 * @throws RemotingException ; * @throws MQBrokerException ; * @throws InterruptedException ; * @throws UnknownHostException ; */ public void endTransaction( final SendResult sendResult, final LocalTransactionState localTransactionState, final Throwable localException) throws RemotingException, MQBrokerException, InterruptedException, UnknownHostException { final MessageId id; if (sendResult.getOffsetMsgId() != null) { id = MessageDecoder.decodeMessageId(sendResult.getOffsetMsgId()); } else { id = MessageDecoder.decodeMessageId(sendResult.getMsgId()); } String transactionId = sendResult.getTransactionId(); final String brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(sendResult.getMessageQueue().getBrokerName()); EndTransactionRequestHeader requestHeader = new EndTransactionRequestHeader(); requestHeader.setTransactionId(transactionId); requestHeader.setCommitLogOffset(id.getOffset()); switch (localTransactionState) { case COMMIT_MESSAGE: requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_COMMIT_TYPE); break; case ROLLBACK_MESSAGE: requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_ROLLBACK_TYPE); break; case UNKNOW: requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_NOT_TYPE); break; default: break; } requestHeader.setProducerGroup(this.defaultMQProducer.getProducerGroup()); requestHeader.setTranStateTableOffset(sendResult.getQueueOffset()); requestHeader.setMsgId(sendResult.getMsgId()); String remark = localException != null ? ("executeLocalTransactionBranch exception: " + localException.toString()) : null; this.mQClientFactory.getMQClientAPIImpl().endTransactionOneway(brokerAddr, requestHeader, remark, this.defaultMQProducer.getSendMsgTimeout()); } /** * 设置callback线程池 * @param callbackExecutor 线程池 */ public void setCallbackExecutor(final ExecutorService callbackExecutor) { this.mQClientFactory.getMQClientAPIImpl().getRemotingClient().setCallbackExecutor(callbackExecutor); } /** * 获取callback线程池 * @return ; */ public ExecutorService getCallbackExecutor() { return this.mQClientFactory.getMQClientAPIImpl().getRemotingClient().getCallbackExecutor(); } /** * 带超时时间的同步发送 * @param msg msg * @param timeout timeout * @return ; * @throws MQClientException ; * @throws RemotingException ; * @throws MQBrokerException ; * @throws InterruptedException ; */ public SendResult send(Message msg, long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException { return this.sendDefaultImpl(msg, CommunicationMode.SYNC, null, timeout); } public ConcurrentMap<String, TopicPublishInfo> getTopicPublishInfoTable() { return topicPublishInfoTable; } public int getZipCompressLevel() { return zipCompressLevel; } public void setZipCompressLevel(int zipCompressLevel) { this.zipCompressLevel = zipCompressLevel; } public ServiceState getServiceState() { return serviceState; } public void setServiceState(ServiceState serviceState) { this.serviceState = serviceState; } public long[] getNotAvailableDuration() { return this.mqFaultStrategy.getNotAvailableDuration(); } public void setNotAvailableDuration(final long[] notAvailableDuration) { this.mqFaultStrategy.setNotAvailableDuration(notAvailableDuration); } public long[] getLatencyMax() { return this.mqFaultStrategy.getLatencyMax(); } public void setLatencyMax(final long[] latencyMax) { this.mqFaultStrategy.setLatencyMax(latencyMax); } public boolean isSendLatencyFaultEnable() { return this.mqFaultStrategy.isSendLatencyFaultEnable(); } public void setSendLatencyFaultEnable(final boolean sendLatencyFaultEnable) { this.mqFaultStrategy.setSendLatencyFaultEnable(sendLatencyFaultEnable); } }