[ISSUE #10764] Complete expired invocation futures - #10765
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses RocketMQ Proxy local-mode hangs by ensuring that when InvocationChannel expires and removes in-flight invocation contexts during cleanup, the associated response futures are completed exceptionally instead of being left pending indefinitely.
Changes:
- Add an
expire(Throwable)hook toInvocationContextInterfaceand implement it inInvocationContextto complete the response future exceptionally. - Update
InvocationChannel.clearExpireContext()to callexpire(...)on expired contexts as they are cleaned up. - Add a unit test covering the “cleanup expires context => future completes exceptionally” behavior and initialize proxy configuration for the test class.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| proxy/src/test/java/org/apache/rocketmq/proxy/service/channel/InvocationChannelTest.java | Adds coverage ensuring expired cleanup completes the response future exceptionally (and initializes proxy config for the test class). |
| proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationContextInterface.java | Introduces an expire(Throwable) lifecycle hook for cleanup expiration handling. |
| proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationContext.java | Implements expire(Throwable) by completing the underlying response CompletableFuture exceptionally. |
| proxy/src/main/java/org/apache/rocketmq/proxy/service/channel/InvocationChannel.java | Completes expired invocation contexts exceptionally during periodic cleanup via clearExpireContext(). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Map.Entry<Integer, InvocationContextInterface> entry = iterator.next(); | ||
| if (entry.getValue().expired(ConfigurationManager.getProxyConfig().getChannelExpiredInSeconds())) { | ||
| iterator.remove(); | ||
| entry.getValue().expire(new RemotingTimeoutException("Invocation context expired. opaque=" + entry.getKey())); |
| boolean expired(long expiredTimeSec); | ||
|
|
||
| default void expire(Throwable throwable) { | ||
| } |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #10765 +/- ##
=============================================
- Coverage 48.29% 48.22% -0.07%
+ Complexity 13499 13483 -16
=============================================
Files 1380 1381 +1
Lines 101093 101097 +4
Branches 13102 13102
=============================================
- Hits 48821 48756 -65
- Misses 46304 46353 +49
- Partials 5968 5988 +20 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
RockteMQ-AI
left a comment
There was a problem hiding this comment.
Review by github-manager-bot
Summary
Adds an expire() method to InvocationContextInterface (default no-op) and implements it in InvocationContext to complete the response future exceptionally with RemotingTimeoutException. InvocationChannel.clearExpireContext() now calls expire() after removing entries, preventing callers from waiting indefinitely on expired invocations.
Findings
- [Correctness]
InvocationChannel.java:71— Theexpire()call is placed afteriterator.remove(), which is correct. The entry is already removed from the map, and the future is completed exceptionally to unblock any waiting caller. - [Correctness]
InvocationContext.java:40-43— The implementation checksresponseFuture != nullbefore completing exceptionally, which avoids NPE. UsingcompleteExceptionallyis the right choice — callers usingwhenCompleteorexceptionallywill properly receive the timeout signal. - [Compatibility]
InvocationContextInterface.java— Addingexpire()as a default method is backward-compatible. Any existing implementations will get the no-op default without breaking. - [Tests]
InvocationChannelTest.java— New testtestClearExpireContextCompletesExpiredFuturesverifies that expired futures are completed exceptionally withRemotingTimeoutException. Good coverage.
Verdict
Clean fix for a real hang scenario. Well-structured with proper interface extension. LGTM.
Automated review by github-manager-bot
Which Issue(s) This PR Fixes
Fixes #10764
Brief Description
InvocationChannel.clearExpireContext()now completes expired invocation contexts exceptionally before removing them from the in-flight request map. This prevents local proxy send/pop callers from waiting forever after cleanup has already expired their request context.How Did You Test This Change?
mvn -pl proxy -Dtest=InvocationChannelTest test