項目中做一個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,在消息日志表里判斷是否已處理過該消息,避免重復消費
