1、
2、
【问题原因】: 消费消息的方法尚未返回结果,或者中断,导致本次消费结果未传回服务端。 【建议方案】: 建议您不要把业务逻辑放在返回给 mq 服务端的代码之前,最好是保证尽快给 到 mq 响应。这样可以避免消息消费失败,在进行消息重试。如果您的业务逻辑时间 的确很长,建议您可以将信息拉取到之后,存到数据库、redis 当中,然后尽快给到 mq ackMessage,之后再异步进行业务消费。
3、
package com.pojo.prj.aliyun.ons;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.mq.http.MQConsumer;
import com.aliyun.mq.http.common.AckMessageException;
import com.aliyun.mq.http.model.Message;
import com.pojo.common.core.utils.StringUtils;
import com.pojo.prj.aliyun.lot.DeviceServiceFactory;
import com.pojo.prj.aliyun.lot.service.DeviceConsumeService;
import com.pojo.common.core.enums.DeviceTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
public class RocketMQMsgHandler implements Runnable {
MQConsumer mqConsumer;
@Override
public void run() {
while (true) {
List<Message> messages = null;
// 长轮询消费消息
// 长轮询表示如果topic没有消息则请求会在服务端挂住3s,3s内如果有消息可以消费则立即返回
try {
messages = mqConsumer.consumeMessage(
1,// 一次最多消费1条(最多可设置为16条)
5// 长轮询时间5秒(最多可设置为30秒)
);
} catch (Exception e) {
//获取消息失败 重连 todo 目前没有环境测试
log.error("获取消息失败====" + e.getMessage() + "====" + e.getClass());
}
// 没有消息
if (CollUtil.isEmpty(messages)) {
continue;
}
// Message.nextConsumeTime前若不确认消息消费成功,则消息会重复消费
// 消息句柄有时间戳,同一条消息每次消费拿到的都不一样
List<String> handles = Lists.newArrayList();
for (Message message : messages) {
handles.add(message.getReceiptHandle());
}
try {
mqConsumer.ackMessage(handles);
} catch (Throwable e) {
// 某些消息的句柄可能超时了会导致确认不成功
if (e instanceof AckMessageException) {
AckMessageException errors = (AckMessageException) e;
log.error("Ack message fail, requestId is:" + errors.getRequestId() + ", fail handles:");
if (errors.getErrorMessages() != null) {
for (String errorHandle : errors.getErrorMessages().keySet()) {
log.error("Handle:" + errorHandle + ", ErrorCode:" + errors.getErrorMessages().get(errorHandle).getErrorCode()
+ ", ErrorMsg:" + errors.getErrorMessages().get(errorHandle).getErrorMessage());
}
}
continue;
}
e.printStackTrace();
continue;
}
// 处理业务逻辑
for (Message message : messages) {
String str = new String(message.getMessageBodyBytes(), StandardCharsets.UTF_8);
JSONObject object = JSONObject.parseObject(str);
String devicetype = object.getString("devicetype");
if (Objects.equals(devicetype, "ZHLZ02")) {
devicetype = "ZHLZ01";
object.put("devicetype", "ZHLZ01");
}
if (StringUtils.isNotBlank(devicetype)) {
DeviceConsumeService service = DeviceServiceFactory.getInstance(DeviceTypeEnum.getValue(devicetype));
if (Objects.nonNull(service)) {
service.consume(object);
}
}
}
}
}
}