项目中做一个ES打标功能,当促销活动变动时(启用、禁用、审核通过等),通过阿里云MNS队列推送消息,消费方监听消息进行业务处理。
因为活动分多钟类型,有的类型门店、商品数量较多,消费处理需要一定时间,基础组件封装了消息消费,在消费完成后会调用阿里云MNS的SDK删除消息,如下:
this.mnsClient.getQueueRef(this.consumerQueue).deleteMessage(message.getReceiptHandle());
日志中发现异常信息:
com.aliyun.mns.common.ServiceException: The receipt handle you provided has expired.
at com.aliyun.mns.common.http.ExceptionResultParser.parse(ExceptionResultParser.java:42)
at com.aliyun.mns.common.http.ExceptionResultParser.parse(ExceptionResultParser.java:12)
at com.aliyun.mns.common.http.HttpCallback.handleResult(HttpCallback.java:155)
at com.aliyun.mns.common.http.HttpCallback.buildResponseMessage(HttpCallback.java:128)
at com.aliyun.mns.common.http.HttpCallback.completed(HttpCallback.java:88)
at com.aliyun.mns.common.http.HttpCallback.completed(HttpCallback.java:22)
at shaded.org.apache.http.concurrent.BasicFuture.completed(BasicFuture.java:119)
at shaded.org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseCompleted(DefaultClientExchangeHandlerImpl.java:177)
at shaded.org.apache.http.nio.protocol.HttpAsyncRequestExecutor.processResponse(HttpAsyncRequestExecutor.java:412)
at shaded.org.apache.http.nio.protocol.HttpAsyncRequestExecutor.inputReady(HttpAsyncRequestExecutor.java:305)
at shaded.org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:267)
at shaded.org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
at shaded.org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
at shaded.org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:116)
at shaded.org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:164)
at shaded.org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:339)
at shaded.org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:317)
同时观察日志发现消息有被重复消费。
查询官方文档:
-
消息服务MNS中删除消息时报“message not exist”的错误
https://help.aliyun.com/knowledge_detail/39218.html -
每条消息会被消费多少次
https://help.aliyun.com/knowledge_detail/175582.html -
队列管理CreateQueue
https://help.aliyun.com/document_detail/35129.html
队列消息消费有个到期时间VisibilityTimeout
,默认为30s。
消息被消费端接收,消息状态从active
变为inactive
,超过VisibilityTimeout
后,又变为active
,然后消息可继续被其他消费端消费,并且消息的ReceiptHandle
失效。
因为消息处理慢超过了30s,因此项目中消费方又接收到了消息,消息的ReceiptHandle
失效因此删除消息报错。
解决方法:
- 方法1:
监听者拿到消息,在记录日志后处理消息前删除消息 - 方法2:
在阿里云后台创建队列的界面中,修改VisibilityTimeout
时间,默认30s调大点,比如改为600s;
同时根据消息id,在消息日志表里判断是否已处理过该消息,避免重复消费