前景回顾

【mq】从零开始实现 mq-01-生产者、消费者启动

【mq】从零开始实现 mq-02-如何实现生产者调用消费者?

【mq】从零开始实现 mq-03-引入 broker 中间人

【mq】从零开始实现 mq-04-启动检测与实现优化

【mq】从零开始实现 mq-05-实现优雅停机

【mq】从零开始实现 mq-06-消费者心跳检测 heartbeat

【mq】从零开始实现 mq-07-负载均衡 load balance

【mq】从零开始实现 mq-08-配置优化 fluent

【mq】从零开始实现 mq-09-消费者拉取消息 pull message

【mq】从零开始实现 mq-10-消费者拉取消息回执 pull message ack

状态回执

大家好,我是老马。

上一节我们只实现了拉取消息的实现,但是缺少了消费状态回执。

这一节我们一起来学习下如何实现状态回执。

代码实现

回执状态的设计

我们规定如下几种回执状态:

package com.github.houbb.mq.common.constant;

/**
* @author binbin.hou
* @since 0.0.3
*/
public final class MessageStatusConst { private MessageStatusConst(){} /**
* 待消费
* ps: 生产者推送到 broker 的初始化状态
*/
public static final String WAIT_CONSUMER = "W"; /**
* 推送给消费端处理中
* ps: broker 准备推送时,首先将状态更新为 P,等待推送结果
* @since 0.1.0
*/
public static final String TO_CONSUMER_PROCESS = "TCP"; /**
* 推送给消费端成功
* @since 0.1.0
*/
public static final String TO_CONSUMER_SUCCESS = "TCS"; /**
* 推送给消费端失败
* @since 0.1.0
*/
public static final String TO_CONSUMER_FAILED = "TCF"; /**
* 消费完成
*/
public static final String CONSUMER_SUCCESS = "CS"; /**
* 消费失败
*/
public static final String CONSUMER_FAILED = "CF"; /**
* 稍后消费
* @since 0.1.0
*/
public static final String CONSUMER_LATER = "CL"; }

消费者状态回执

我们在消费之后,添加状态回执:

for(MqMessage mqMessage : mqMessageList) {
IMqConsumerListenerContext context = new MqConsumerListenerContext();
final String messageId = mqMessage.getTraceId();
ConsumerStatus consumerStatus = mqListenerService.consumer(mqMessage, context);
log.info("消息:{} 消费结果 {}", messageId, consumerStatus); // 状态同步更新
MqCommonResp ackResp = consumerBrokerService.consumerStatusAck(messageId, consumerStatus);
log.info("消息:{} 状态回执结果 {}", messageId, JSON.toJSON(ackResp));
}

回执实现,根据 messageId 更新对应的消息消费状态。

public MqCommonResp consumerStatusAck(String messageId, ConsumerStatus consumerStatus) {
final MqConsumerUpdateStatusReq req = new MqConsumerUpdateStatusReq();
req.setMessageId(messageId);
req.setMessageStatus(consumerStatus.getCode());
final String traceId = IdHelper.uuid32();
req.setTraceId(traceId);
req.setMethodType(MethodType.C_CONSUMER_STATUS); // 重试
return Retryer.<MqCommonResp>newInstance()
.maxAttempt(consumerStatusMaxAttempt)
.callable(new Callable<MqCommonResp>() {
@Override
public MqCommonResp call() throws Exception {
Channel channel = getChannel(null);
MqCommonResp resp = callServer(channel, req, MqCommonResp.class);
if(!MqCommonRespCode.SUCCESS.getCode().equals(resp.getRespCode())) {
throw new MqException(ConsumerRespCode.CONSUMER_STATUS_ACK_FAILED);
}
return resp;
}
}).retryCall();
}

Broker 回执处理

消息分发

// 消费者消费状态 ACK
if(MethodType.C_CONSUMER_STATUS.equals(methodType)) {
MqConsumerUpdateStatusReq req = JSON.parseObject(json, MqConsumerUpdateStatusReq.class);
final String messageId = req.getMessageId();
final String messageStatus = req.getMessageStatus();
return mqBrokerPersist.updateStatus(messageId, messageStatus);
}

简单实现

这里是基于本地 map 更新状态的,性能比较差。

后续会以 mysql 实现。

public MqCommonResp updateStatus(String messageId, String status) {
// 这里性能比较差,所以不可以用于生产。仅作为测试验证
for(List<MqMessagePersistPut> list : map.values()) {
for(MqMessagePersistPut put : list) {
MqMessage mqMessage = put.getMqMessage();
if(mqMessage.getTraceId().equals(messageId)) {
put.setMessageStatus(status);
break;
}
}
} MqCommonResp commonResp = new MqCommonResp();
commonResp.setRespCode(MqCommonRespCode.SUCCESS.getCode());
commonResp.setRespMessage(MqCommonRespCode.SUCCESS.getMsg());
return commonResp;
}

小结

对于消息状态的细化,更加便于我们后续的管理,和问题的定位。

希望本文对你有所帮助,如果喜欢,欢迎点赞收藏转发一波。

我是老马,期待与你的下次重逢。

开源地址

The message queue in java.(java 简易版本 mq 实现) https://github.com/houbb/mq

拓展阅读

rpc-从零开始实现 rpc https://github.com/houbb/rpc

【mq】从零开始实现 mq-10-消费者拉取消息回执 pull message ack的更多相关文章

  1. 【mq】从零开始实现 mq-09-消费者拉取消息 pull message

    前景回顾 [mq]从零开始实现 mq-01-生产者.消费者启动 [mq]从零开始实现 mq-02-如何实现生产者调用消费者? [mq]从零开始实现 mq-03-引入 broker 中间人 [mq]从零 ...

  2. kafka 消费者拉取消息

    本文只跟踪消费者拉取消息的流程.对于 java 客户端, kafka 的生产者和消费者复用同一个网络 io 类 NetworkClient. 入口在 KafkaConsumer#pollOnce 中, ...

  3. 【mq】从零开始实现 mq-11-消费者消息回执添加分组信息 pull message ack groupName

    前景回顾 [mq]从零开始实现 mq-01-生产者.消费者启动 [mq]从零开始实现 mq-02-如何实现生产者调用消费者? [mq]从零开始实现 mq-03-引入 broker 中间人 [mq]从零 ...

  4. RocketMQ入门(3)拉取消息

    转自:http://www.changeself.net/archives/rocketmq入门(3)拉取消息.html RocketMQ入门(3)拉取消息 RocketMQ不止可以直接推送消息,在消 ...

  5. git 拉取和获取 pull 和 fetch 区别

    使用Git  直接提交的话   直接 push 获取最新版本  有两种  拉取 和 获取 pull 和 fetch git  pull     从远程拉取最新版本 到本地  自动合并 merge   ...

  6. RocketMQ 拉取消息-文件获取

    看完了上一篇的<RocketMQ 拉取消息-通信模块>,请求进入PullMessageProcessor中,接着 PullMessageProcessor.processRequest(f ...

  7. git 拉取和获取 pull 和 fetch 区别【转】

    本文转载自:http://blog.csdn.net/u010094934/article/details/52775653 使用git  直接提交的话   直接 push 获取最新版本  有两种   ...

  8. Kafka消费者拉取数据异常Unexpected error code 2 while fetching data

    Kafka消费程序间歇性报同一个错: 上网没查到相关资料,只好自己分析.通过进一步分析日志发现,只有在拉取某一个特定的topic的数据时报错,如果拉取其他topic的数据则不会报错.而从这个异常信息来 ...

  9. Linux 搭建git 自己拉取本地 git pull,其他地方的git仓库拉取代码

    Linux 下建立 Git 与 GitHub 的连接 Git 是一款开源的分布式版本控制系统,而 GitHub 是依托 Git 的代码托管平台. GitHub 利用 Git 极其强大的克隆和分支功能, ...

随机推荐

  1. Redis缓存穿透、缓存雪崩、缓存击穿

    缓存穿透: ​ 缓存穿透,是指查询一个数据库一定不存在的数据.正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的对象,放进缓存.如果 ...

  2. 乱序数组中第k大的数(顺序统计量)

    该问题是顺序统计量中十分经典的问题. 使用快排中的分区法,将第k大的数排序.若双向扫描分区加上三点中值法或绝对中值法,可以保证在 O(n) 时间里找出第k大的数. 补充:可以直接使用C++STL中的n ...

  3. BMZCTF phar???

    pchar??? 补充知识点 开始这题之前我们先补充一个知识点 phar 的文件包含 和上面类似先创建一个phar 标准包,使用 PharData 来创建,然后添加文件进去phar里面. 然后在文件包 ...

  4. Redis报错:DENIED Redis is running in protected mode

    转:Redis使用认证密码登录   Redis默认配置是不需要密码认证的,也就是说只要连接的Redis服务器的host和port正确,就可以连接使用.这在安全性上会有一定的问题,所以需要启用Redis ...

  5. TOP 10 开源的推荐系统简介

      最 近这两年推荐系统特别火,本文搜集整理了一些比较好的开源推荐系统,即有轻量级的适用于做研究的SVDFeature.LibMF.LibFM等,也有重 量级的适用于工业系统的 Mahout.Oryx ...

  6. ES6-11学习笔记--const

    新声明方式:const 1.不属于顶层对象 window 2.不允许重复声明 3.不存在变量提升 4.暂时性死区 5.块级作用域   以上特性跟let声明一样,特性可看 let 的学习笔记:链接跳转 ...

  7. java中为什么把Checked Exception翻译成受检的异常?

    6.Checked Exception(受检的异常) 马克-to-win:为什么我大胆的把Checked Exception翻译成受检的异常?因为这类异常,编译器检查发现到它后会强令你catch它或t ...

  8. 【Android开发】【布局】各种TabLayout样式

    Demo

  9. Idea中配置Tomcat以及运行maven项目

    maven安装和详细配置 提示:下面是Tomcat9.0版本的下载链接,需要其他版本的去官方网站下载. 链接:https://pan.baidu.com/s/1CONf8KVXM4gyJj4pxjFB ...

  10. Java报错:Injection of resource dependencies failed

    在学习springMVC+Mabatis的时候,添加注解@Resource报错 Injection of resource dependencies failed de完bug后发现有几个点注意一下, ...