DefaultMQProducer.send(message, timeout)的消息发送状态sendResult.getSendStatus()不可用性

来源:互联网 发布:手机usb共享网络打不开 编辑:程序博客网 时间:2024/05/21 22:28

使用DefaultMQProducer.send(message,timeout);可以通过sendResult.getSendStatus()查看发送到RocketMQ的信息是否发送成功,在使用如下代码进行发送信息,并对信息发送是否确认成功,如果不成功进行重新发送时,出现bug:

public class MQProductor {    private static final Logger logger = LoggerFactory.getLogger(MQProductor.class);    private static DefaultMQProducer producer = null;    private static MQProductor instance = null;    private MQProductor(){}    public static MQProductor getInstance(){        if(instance == null || producer == null){            synchronized (MQProductor.class){                if(instance == null){                    instance = new MQProductor();                }                if(producer == null){                    initProducer();                }            }        }        return instance;    }    private static void initProducer(){        /**         * 一个应用创建一个Producer,由应用来维护此对象,可以设置为全局对象或者单例<br>         * 注意:ProducerGroupName需要由应用来保证唯一<br>         * ProducerGroup这个概念发送普通的消息时,作用不大,但是发送分布式事务消息时,比较关键,         * 因为服务器会回查这个Group下的任意一个Producer         */        String groupName = ConnServerConfig.getPropValue("MQ_PRODUCER_GROUP_NAME", "liveConnMPhone");        String addr = ConnServerConfig.getPropValue("MQ_NAMESERVER_ADDR");        String producerName = ConnServerConfig.getPropValue("MQ_PRODUCTER_NAME");        producer = new DefaultMQProducer(groupName);        producer.setNamesrvAddr(addr);        producer.setInstanceName(producerName);        /**         * Producer对象在使用之前必须要调用start初始化,初始化一次即可<br>         * 注意:切记不可以在每次发送消息时,都调用start方法         */        try {            producer.start();        } catch (MQClientException e) {            logger.error("初始化RocketMQ异常,将推出程序" + e.getMessage(), e);            SystemResourcesClean.closeAllResources();            System.exit(-1);        }    }    public static void closeProducer(){        if(producer != null){            producer.shutdown();            producer = null;        }    }    public boolean sendMsg(@NotNull String topic, @NotNull String tags, @NotNull String keys, @NotNull String msg) throws UnsupportedEncodingException {        int count = 0;        boolean status = false;        long timeout = Long.parseLong(ConnServerConfig.getPropValue("MQ_SENT_TIMEOUT", "4000"));        Message message = new Message(topic, tags, keys, msg.getBytes("UTF-8"));        logger.debug("count:" + count);        while(count <= 3){            logger.debug("进入循环");            try {                SendResult sendResult = producer.send(message, timeout);                logger.debug("发送MQ状态:" + sendResult.getSendStatus());                if(sendResult.getSendStatus() == SendStatus.SEND_OK){                    status = true;                    break;                }            } catch (InterruptedException e) {                logger.error("MQ发送消息:" + count + "次失败,请查看一次原因" + e.getMessage(), e);            } catch (RemotingException e) {                logger.error("MQ发送消息:" + count + "次失败,请查看一次原因" + e.getMessage(), e);            } catch (MQClientException e) {                logger.error("MQ发送消息:" + count + "次失败,请查看一次原因" + e.getMessage(), e);            } catch (MQBrokerException e) {                logger.error("MQ发送消息:" + count + "次失败,请查看一次原因" + e.getMessage(), e);            }finally {                count++;            }        }        return status;    }}


背景,connserver负责解释请求,将不同类型的请求数据发送到RocketMQ的不同队列中,roomserver负责从RocketMQ中获取数据,并根据数据类型进行对应的处理,将处理结果通过RPC回调给connserver。
这时会出现一个问题,在roomserver已经处理完connserver发送到RocketMQ中的数据并且通过RPC回调到connserver中,这时sendResult.getSendStatus()还未返回发送消息是否成功的状态,明明消息已经发送成功并且已经被roomserver消费了,状态还未返回,表明这个方法的不可用,状态返回严重滞后。
解决方案:sendResult.getSendStatus()这个方法返回的结果只用于判定是否需要对消息进行重新发送,不用其返回的结果作为逻辑流程的处理依据,消息发送并处理成功自然会经过RPC回调,消息未发送成功roomserver没有接受到消息也不会触发RPC回调。

0 0
原创粉丝点击