feat: add Timeout pattern (#2845) - #3598
Conversation
PR SummaryIntegrated the Timeout pattern as a new module, introducing per-service timeouts, cancellation, and fallback handling to prevent slow dependencies from stalling the system. The module includes core components (TimeoutPolicy, TimeoutExecutor, TimeoutMetrics), a simulated DownstreamService and App wiring, plus comprehensive tests and documentation with a PlantUML diagram. Changes
autogenerated by presubmit.ai |
There was a problem hiding this comment.
🚨 Pull request needs attention.
Review Summary
Files Processed (16)
- pom.xml (1 hunk)
- timeout/README.md (1 hunk)
- timeout/etc/timeout.urm.puml (1 hunk)
- timeout/pom.xml (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/App.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/ProductCatalogService.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/RecommendationService.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/ServiceCallException.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutExecutor.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutMetrics.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutPolicy.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutRegistry.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/AppTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/TimeoutExecutorTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/TimeoutPolicyTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/TimeoutRegistryTest.java (1 hunk)
Actionable Comments (7)
-
timeout/src/main/java/com/iluwatar/timeout/App.java [61-61]
possible bug: "Logger name should match Lombok's @slf4j field"
-
timeout/src/main/java/com/iluwatar/timeout/App.java [67-67]
readability: "Use the Lombok 'log' logger"
-
timeout/src/main/java/com/iluwatar/timeout/App.java [73-73]
readability: "Use the Lombok 'log' logger"
-
timeout/src/main/java/com/iluwatar/timeout/App.java [81-81]
readability: "Use the Lombok 'log' logger for final status"
-
timeout/src/main/java/com/iluwatar/timeout/ProductCatalogService.java [59-59]
possible bug: "Logger field name mismatch in ProductCatalogService"
-
timeout/src/main/java/com/iluwatar/timeout/RecommendationService.java [60-66]
possible bug: "Logger field name mismatch in RecommendationService"
-
timeout/src/main/java/com/iluwatar/timeout/TimeoutExecutor.java [82-82]
possible bug: "Logger name mismatch in TimeoutExecutor"
Skipped Comments (1)
-
timeout/pom.xml [46-50]
enhancement: "Add junit-jupiter-api for tests"
|
Note on the automated review comments: |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3598 +/- ##
============================================
+ Coverage 83.79% 83.87% +0.07%
- Complexity 4277 4302 +25
============================================
Files 1121 1127 +6
Lines 15144 15230 +86
Branches 723 726 +3
============================================
+ Hits 12690 12774 +84
- Misses 2159 2161 +2
Partials 295 295 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Follow-up on the Codecov note: added a test for an interrupted caller in |
There was a problem hiding this comment.
🚨 Pull request needs attention.
Review Summary
Files Processed (17)
- pom.xml (1 hunk)
- timeout/README.md (1 hunk)
- timeout/etc/timeout.urm.puml (1 hunk)
- timeout/pom.xml (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/App.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/ProductCatalogService.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/RecommendationService.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/ServiceCallException.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutExecutor.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutMetrics.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutPolicy.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutRegistry.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/AppTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/RecommendationServiceTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/TimeoutExecutorTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/TimeoutPolicyTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/TimeoutRegistryTest.java (1 hunk)
Actionable Comments (3)
-
timeout/src/main/java/com/iluwatar/timeout/App.java [61-61]
readability: "Replace Lombok-generated logger usage with 'log'."
-
timeout/src/main/java/com/iluwatar/timeout/ProductCatalogService.java [59-59]
readability: "Use Lombok 'log' instead of 'LOGGER' in logging."
-
timeout/src/main/java/com/iluwatar/timeout/RecommendationService.java [60-64]
readability: "Replace Lombok-generated logger usage with 'log' in multi-line logging."
Skipped Comments (0)
|
Coverage follow-up: extracted the two demo calls in |
There was a problem hiding this comment.
✅ LGTM!
Review Summary
Files Processed (17)
- pom.xml (1 hunk)
- timeout/README.md (1 hunk)
- timeout/etc/timeout.urm.puml (1 hunk)
- timeout/pom.xml (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/App.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/ProductCatalogService.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/RecommendationService.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/ServiceCallException.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutExecutor.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutMetrics.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutPolicy.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutRegistry.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/AppTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/RecommendationServiceTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/TimeoutExecutorTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/TimeoutPolicyTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/TimeoutRegistryTest.java (1 hunk)
Actionable Comments (0)
Skipped Comments (8)
-
timeout/src/main/java/com/iluwatar/timeout/App.java [61-61]
best_practice: "Use Lombok's generated logger"
-
timeout/src/main/java/com/iluwatar/timeout/App.java [67-67]
best_practice: "Use Lombok's generated logger"
-
timeout/src/main/java/com/iluwatar/timeout/App.java [73-73]
best_practice: "Use Lombok's generated logger"
-
timeout/src/main/java/com/iluwatar/timeout/App.java [75-75]
best_practice: "Use Lombok's generated logger"
-
timeout/src/main/java/com/iluwatar/timeout/ProductCatalogService.java [59-59]
best_practice: "Use Lombok's generated logger"
-
timeout/src/main/java/com/iluwatar/timeout/RecommendationService.java [60-66]
best_practice: "Use Lombok's generated logger"
-
timeout/src/main/java/com/iluwatar/timeout/TimeoutExecutor.java [82-82]
best_practice: "Use Lombok's generated logger"
-
timeout/src/main/java/com/iluwatar/timeout/TimeoutExecutor.java [88-90]
best_practice: "Use Lombok's generated logger"
There was a problem hiding this comment.
✅ LGTM!
Review Summary
Commits Considered (3)
- afd73f2: docs: embed the rendered class diagram in the timeout README
Render etc/timeout.urm.puml to PNG and embed it in the detailed explanation section, matching the other modules, instead of the inline mermaid block.
- 4d79669: refactor: drop timeout registry and merge the demo services
TimeoutRegistry was configuration scaffolding rather than part of the
pattern, so App now builds its TimeoutPolicy values directly.
ProductCatalogService and RecommendationService only differed in name,
latency and payload, so they collapse into a single parameterised
DownstreamService and App's two near-identical helpers into one call
helper.
README, PlantUML diagram and tests follow; the sample output block is
taken from a real run of the demo.
-
9124ada: fix: keep metrics snapshot sorted and translate rejected submissions
-
TimeoutMetrics.snapshot() returns an unmodifiable SortedMap so the sorted view promised by its javadoc survives, covered by a new ordering test
-
TimeoutExecutor submits inside the try and wraps RejectedExecutionException in ServiceCallException, matching its @throws contract
-
timeout.urm.puml: mark TimeoutPolicy as a record, drop the synthetic App constructor, show ServiceCallException extending RuntimeException, add the App to TimeoutPolicy and TimeoutMetrics dependencies
-
README: inline mermaid class diagram instead of the raw .puml link, and note that the timeout warning and the worker interrupt lines may interleave
Files Processed (10)
- timeout/README.md (1 hunk)
- timeout/etc/timeout.urm.png (0 hunks)
- timeout/etc/timeout.urm.puml (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/App.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/DownstreamService.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutExecutor.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutMetrics.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/AppTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/DownstreamServiceTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/TimeoutExecutorTest.java (1 hunk)
Actionable Comments (0)
Skipped Comments (10)
-
timeout/src/main/java/com/iluwatar/timeout/App.java [66-66]
best_practice: "Use Lombok's log field instead of LOGGER"
-
timeout/src/main/java/com/iluwatar/timeout/App.java [69-69]
best_practice: "Replace LOGGER with log for per-call logging"
-
timeout/src/main/java/com/iluwatar/timeout/App.java [71-71]
best_practice: "Replace LOGGER with log for products logging"
-
timeout/src/main/java/com/iluwatar/timeout/App.java [73-73]
best_practice: "Replace LOGGER with log for recommendations logging"
-
timeout/src/main/java/com/iluwatar/timeout/App.java [75-75]
best_practice: "Replace LOGGER with log for final recommendations payload"
-
timeout/src/main/java/com/iluwatar/timeout/App.java [77-77]
best_practice: "Replace LOGGER with log for timeout metrics"
-
timeout/src/main/java/com/iluwatar/timeout/DownstreamService.java [74-74]
best_practice: "Use Lombok's log instead of LOGGER in DownstreamService"
-
timeout/src/main/java/com/iluwatar/timeout/DownstreamService.java [78-78]
best_practice: "Use Lombok's log in DownstreamService on interruption"
-
timeout/src/main/java/com/iluwatar/timeout/TimeoutExecutor.java [86-86]
best_practice: "Use Lombok's log for successful completion logging"
-
timeout/src/main/java/com/iluwatar/timeout/TimeoutExecutor.java [92-92]
best_practice: "Replace timeout warning log with log"
The metrics snapshot stays sorted, a rejected submission surfaces as ServiceCallException, TimeoutRegistry is dropped and the two demo services merge into DownstreamService. The class diagram is a rendered PNG.
There was a problem hiding this comment.
✅ LGTM!
Review Summary
Commits Considered (1)
- 2458cf8: refactor: simplify the timeout demo and address review findings
The metrics snapshot stays sorted, a rejected submission surfaces as ServiceCallException, TimeoutRegistry is dropped and the two demo services merge into DownstreamService. The class diagram is a rendered PNG.
Files Processed (10)
- timeout/README.md (1 hunk)
- timeout/etc/timeout.urm.png (0 hunks)
- timeout/etc/timeout.urm.puml (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/App.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/DownstreamService.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutExecutor.java (1 hunk)
- timeout/src/main/java/com/iluwatar/timeout/TimeoutMetrics.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/AppTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/DownstreamServiceTest.java (1 hunk)
- timeout/src/test/java/com/iluwatar/timeout/TimeoutExecutorTest.java (1 hunk)
Actionable Comments (0)
Skipped Comments (3)
-
timeout/src/main/java/com/iluwatar/timeout/App.java [66-77]
readability: "Use the Lombok-provided logger instead of LOGGER"
-
timeout/src/main/java/com/iluwatar/timeout/DownstreamService.java [73-82]
readability: "Logger usage mismatch in DownstreamService"
-
timeout/src/main/java/com/iluwatar/timeout/TimeoutExecutor.java [86-93]
readability: "Logger usage mismatch in TimeoutExecutor"
What does this PR do?
Adds the Timeout pattern as a new
timeoutmodule.TimeoutPolicy. When the limit is exceeded the call is cancelled with an interrupt, the event is logged and counted, and a fallback answer is returned.TimeoutPolicy(record) andTimeoutRegistry: per-service configurable limits with a default.TimeoutExecutor: enforces the limit (Future.get(timeout)), cancels the overrunning call, records the event inTimeoutMetrics, invokes the fallback. Service failures are surfaced asServiceCallException, not as timeouts.ProductCatalogService(fast) andRecommendationService(slow, interruptible): simulated dependencies.App: catalog answers within its 500 ms limit; recommendations exceed their 100 ms limit, get cancelled and replaced by popular items; timeout counters are printed. Logging traces every step.README.md: intent, real-world example, sequence diagram, code walkthrough, applicability, trade-offs, related patterns (including how this differs from the existingfallbackmodule, where the time limit is only one of several triggers). PlantUML class diagram underetc/.AppTest.pom.xml../mvnw clean verify -pl timeoutpasses locally on JDK 21 and inside aneclipse-temurin:21container.Fixes #2845