RocketMQ同步消息发送失败重试DEMO

producer.setRetryTimesWhenSendFailed(3);

通过设置可以设置同步消息重试次数

重试是通过MQ内部去实现。具体到DefaultMQProducerImpl的sendDefaultImpl方法

    private SendResult sendDefaultImpl(Message msg, CommunicationMode communicationMode, SendCallback sendCallback, long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
        this.makeSureStateOK();
        Validators.checkMessage(msg, this.defaultMQProducer);
        long invokeID = this.random.nextLong();
        long beginTimestampFirst = System.currentTimeMillis();
        long beginTimestampPrev = beginTimestampFirst;
        TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic());
        if (topicPublishInfo != null && topicPublishInfo.ok()) {
            boolean callTimeout = false;
            MessageQueue mq = null;
            Exception exception = null;
            SendResult sendResult = null;
            int timesTotal = communicationMode == CommunicationMode.SYNC ? 1 + this.defaultMQProducer.getRetryTimesWhenSendFailed() : 1;
            int times = 0;
            String[] brokersSent = new String[timesTotal];

            while(true) {
                label117: {
                    String info;
                    if (times < timesTotal) {
                        info = null == mq ? null : mq.getBrokerName();
                        MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, info);
                        if (mqSelected != null) {
                            mq = mqSelected;
                            brokersSent[times] = mqSelected.getBrokerName();

                            long endTimestamp;
                            try {
                                beginTimestampPrev = System.currentTimeMillis();
                                if (times > 0) {
                                    msg.setTopic(this.defaultMQProducer.withNamespace(msg.getTopic()));
                                }

                                long costTime = beginTimestampPrev - beginTimestampFirst;
                                if (timeout >= costTime) {
                                    sendResult = this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout - costTime);
                                    endTimestamp = System.currentTimeMillis();
                                    this.updateFaultItem(mq.getBrokerName(), endTimestamp - beginTimestampPrev, false);
                                    switch(communicationMode) {
                                    case ASYNC:
                                        return null;
                                    case ONEWAY:
                                        return null;
                                    case SYNC:
                                        if (sendResult.getSendStatus() == SendStatus.SEND_OK || !this.defaultMQProducer.isRetryAnotherBrokerWhenNotStoreOK()) {
                                            return sendResult;
                                        }
                                    default:
                                        break label117;
                                    }
                                }

                                callTimeout = true;
                            } catch (RemotingException var26) {
                                endTimestamp = System.currentTimeMillis();
                                this.updateFaultItem(mqSelected.getBrokerName(), endTimestamp - beginTimestampPrev, true);
                                this.log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mqSelected), var26);
                                this.log.warn(msg.toString());
                                exception = var26;
                                break label117;
                            } catch (MQClientException var27) {
                                endTimestamp = System.currentTimeMillis();
                                this.updateFaultItem(mqSelected.getBrokerName(), endTimestamp - beginTimestampPrev, true);
                                this.log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mqSelected), var27);
                                this.log.warn(msg.toString());
                                exception = var27;
                                break label117;
                            } catch (MQBrokerException var28) {
                                endTimestamp = System.currentTimeMillis();
                                this.updateFaultItem(mqSelected.getBrokerName(), endTimestamp - beginTimestampPrev, true);
                                this.log.warn(String.format("sendKernelImpl exception, resend at once, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mqSelected), var28);
                                this.log.warn(msg.toString());
                                exception = var28;
                                if (this.defaultMQProducer.getRetryResponseCodes().contains(var28.getResponseCode())) {
                                    break label117;
                                }

                                if (sendResult != null) {
                                    return sendResult;
                                }

                                throw var28;
                            } catch (InterruptedException var29) {
                                endTimestamp = System.currentTimeMillis();
                                this.updateFaultItem(mqSelected.getBrokerName(), endTimestamp - beginTimestampPrev, false);
                                this.log.warn(String.format("sendKernelImpl exception, throw exception, InvokeID: %s, RT: %sms, Broker: %s", invokeID, endTimestamp - beginTimestampPrev, mqSelected), var29);
                                this.log.warn(msg.toString());
                                this.log.warn("sendKernelImpl exception", var29);
                                this.log.warn(msg.toString());
                                throw var29;
                            }
                        }
                    }

                    if (sendResult != null) {
                        return sendResult;
                    }

                    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 = info + FAQUrl.suggestTodo("http://rocketmq.apache.org/docs/faq/");
                    MQClientException mqClientException = new MQClientException(info, (Throwable)exception);
                    if (callTimeout) {
                        throw new RemotingTooMuchRequestException("sendDefaultImpl call timeout");
                    }

                    if (exception instanceof MQBrokerException) {
                        mqClientException.setResponseCode(((MQBrokerException)exception).getResponseCode());
                    } else if (exception instanceof RemotingConnectException) {
                        mqClientException.setResponseCode(10001);
                    } else if (exception instanceof RemotingTimeoutException) {
                        mqClientException.setResponseCode(10002);
                    } else if (exception instanceof MQClientException) {
                        mqClientException.setResponseCode(10003);
                    }

                    throw mqClientException;
                }

                ++times;
            }
        } else {
            this.validateNameServerSetting();
            throw (new MQClientException("No route info of this topic: " + msg.getTopic() + FAQUrl.suggestTodo("http://rocketmq.apache.org/docs/faq/"), (Throwable)null)).setResponseCode(10005);
        }
    }

可以看到RemotingException、MQClientException、MQBrokerException时,Producer会自动重投消息,同步消息的重试选择其它Broker

如果超过了设定重试次数,就会抛出异常

        try {
            SendResult send = producer.send(msg);
            System.out.println(send);

        } catch (Exception e) {
            System.out.println("发送失败:"+e.getMessage());
            while (true){
                System.out.println("sleep");
                Thread.sleep(2000);
                SendResult result = producer.send(msg);
                if(result.getSendStatus().equals(SendStatus.SEND_OK)){
                    break;
                }
                System.out.println(result);
                System.out.println("again");
            }
        }

实际情况可以根据业务需求改动,比如一定要发送成功的,后期每次重试休眠的时间随着重试次数增加。或者可以根据key 来记录,每个key 只能重试几次。随后就记录,通知。

阿里云RocketMQ是一种分布式消息中间件,它支持发布/订阅模型,常用于大规模、高并发的消息处理场景。关于发送延迟消息RocketMQ提供了一种特殊模式——顺序消息(Order Message),可以满足需要消息按序到达消费者的需求,包括延时送达。 以下是使用Java SDK发送延迟消息的一个简单示例: ```java import com.alipay.cloud.smgk.Client; import com.alipay.cloud.smgk.message.Message; public class DelayMessageDemo { public static void main(String[] args) { // 创建客户端实例 Client client = new Client("your-access-key-id", "your-access-key-secret", "your-endpoint"); try { // 发送延迟消息 Message message = new Message( "queueName", // 消息队列名 "tag", // 分区标签 "delayKey", // 延迟键,用于控制消息何时投递 "your-delay-time-in-second", // 指定的延迟时间(单位秒) "delayMessageBody" // 消息内容 ); // 设置生产者属性,如序列化方式等 message.setProducerGroup("producer-group"); message.setSerializerClassName("com.alibaba.rocketmq.common.serializer.StringSerializer"); // 发送延迟消息 client.sendMessage(message); System.out.println("延迟消息已成功发送RocketMQ"); } catch (Exception e) { e.printStackTrace(); } finally { client.shutdown(); } } } ``` 在这个例子中,你需要替换`your-access-key-id`、`your-access-key-secret`和`your-endpoint`为你实际的访问密钥、访问密钥秘密以及服务地址。同时,记得设置合适的延迟时间和序列化策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值