客戶環境中大量 JMS 訊息停留在 receive 狀態,需重啟 JMS Server 或 WebLogic Server 才能被消費。經排查為 WebLogic 潛在 Bug,亦可能與環境(如 NTP 時間同步)有關。
receive:訊息已被 Consumer 取走,但 Server 端未收到 ACK,訊息無法從 Queue 刪除,且不可被其他 Consumer 消費(Point-to-Point 模型)。consumer.receive() 返回前,Client 層自動發送 ACK。message.acknowledge()。
java.lang.IllegalArgumentException: Delay is negative.
at weblogic.timers.internal.TimerManagerImpl.schedule(...)
at weblogic.messaging.kernel.internal.ReceiveRequestImpl.<init>(...)
at weblogic.jms.backend.BEConsumerImpl.blockingReceiveStart(...)
...
關鍵點:TimerManagerImpl.schedule 因負數 timeout 拋出異常。
JMSConsumer.receive(timeout) → JMSSession.receiveMessage() 建立 FEConsumerReceiveRequest,經 FrontEnd Dispatcher 傳至 BackEnd。BEConsumerImpl.receive() → blockingReceiveStart() 呼叫 QueueImpl.receive()。QueueImpl.receive() 初始化 ReceiveRequestImpl,若無匹配訊息,呼叫 addReader() 註冊等待者,並啟動 Timer 等待 timeout。Client 指定 timeout=1,經內部計算變為負數,導致 TimerManagerImpl.schedule() 拋出 IllegalArgumentException。關鍵缺陷:異常拋出前,ReceiveRequestImpl 已被加入 QueueImpl.readerList,但異常處理未將其移除。
QueueImpl.match() 發現 readerList 中有等待者,將訊息標記 receive 並移入 Pending List。JMSConsumer 已因異常關閉,訊息無法 Deliver 至 Client,亦無 ACK 返回。receiveNoWait() 或明確設定合理 timeout,並加強異常處理與資源清理。若訊息狀態為 transaction,通常表示發送未完成或處於刪除事務中,屬不同問題域。