Skip to content

Commit 87fdf74

Browse files
committed
Add Timeout pattern implementation - Fixes #2845
1 parent ede37bd commit 87fdf74

File tree

8 files changed

+836
-0
lines changed

8 files changed

+836
-0
lines changed

timeout/README.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# Timeout Pattern
2+
3+
## Intent
4+
Prevent operations from blocking indefinitely by setting a maximum time limit for their completion. If the operation doesn't complete within the specified timeout period, it is cancelled and control is returned to the caller with an error.
5+
6+
## Explanation
7+
8+
Real-world example
9+
10+
> Consider a restaurant where customers place orders. The kitchen has a policy that if a dish cannot be prepared within 30 minutes, the order is cancelled and the customer is notified. This prevents customers from waiting indefinitely and allows them to make alternative arrangements.
11+
12+
In plain words
13+
14+
> The Timeout pattern ensures that operations complete within a specified time limit, preventing indefinite blocking and improving system responsiveness.
15+
16+
**Programmatic Example**
17+
18+
The Timeout pattern is implemented using the `TimeoutHandler` class which wraps operations and enforces time constraints:
19+
20+
```java
21+
TimeoutHandler handler = new TimeoutHandler();
22+
23+
// Execute a task with 3 second timeout
24+
try {
25+
String result = handler.execute(() -> {
26+
// Simulate some processing
27+
Thread.sleep(1000);
28+
return "Operation completed";
29+
}, 3, TimeUnit.SECONDS);
30+
31+
System.out.println(result);
32+
} catch (TimeoutException e) {
33+
System.err.println("Operation timed out: " + e.getMessage());
34+
}
35+
```
36+
37+
The `TimeoutHandler` uses an `ExecutorService` to run tasks asynchronously and monitors their completion:
38+
39+
```java
40+
public <T> T execute(Callable<T> task, long timeout, TimeUnit unit)
41+
throws TimeoutException {
42+
Future<T> future = executor.submit(task);
43+
44+
try {
45+
return future.get(timeout, unit);
46+
} catch (java.util.concurrent.TimeoutException e) {
47+
future.cancel(true);
48+
throw new TimeoutException("Operation timed out", e);
49+
}
50+
}
51+
```
52+
53+
## Class diagram
54+
55+
![Timeout Pattern UML](./etc/timeout.urm.png)
56+
57+
## Applicability
58+
59+
Use the Timeout pattern when:
60+
61+
- Operations might block indefinitely due to network issues, slow services, or resource contention
62+
- You need to maintain system responsiveness even when dependencies are slow
63+
- Cascading failures need to be prevented in distributed systems
64+
- SLA requirements mandate maximum response times
65+
- You want to implement circuit breaker or retry patterns
66+
67+
## Known Uses
68+
69+
- HTTP client libraries (setting connection and read timeouts)
70+
- Database connection pools (query timeouts)
71+
- Microservices communication (service-to-service call timeouts)
72+
- Message queue consumers (message processing timeouts)
73+
- RPC frameworks (remote procedure call timeouts)
74+
75+
## Consequences
76+
77+
Benefits:
78+
- Prevents indefinite blocking and resource exhaustion
79+
- Improves system responsiveness and user experience
80+
- Enables better error handling and recovery strategies
81+
- Helps maintain SLA commitments
82+
- Prevents cascading failures in distributed systems
83+
84+
Trade-offs:
85+
- Requires careful tuning of timeout values
86+
- May need retry logic for transient failures
87+
- Can increase system complexity
88+
- Might cancel operations that would have eventually succeeded
89+
90+
## Related Patterns
91+
92+
- Circuit Breaker: Often used together; circuit breaker opens after multiple timeout failures
93+
- Retry: Used to handle timeout exceptions by retrying the operation
94+
- Bulkhead: Isolates resources to prevent timeout cascades
95+
- Async Method Invocation: Provides non-blocking execution with timeout support
96+
97+
## Credits
98+
99+
- [Microsoft Azure - Timeout Pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/timeout)
100+
- [Release It!: Design and Deploy Production-Ready Software](https://www.amazon.com/Release-Design-Deploy-Production-Ready-Software/dp/1680502395)
101+
- [Building Microservices: Designing Fine-Grained Systems](https://www.amazon.com/Building-Microservices-Designing-Fine-Grained-Systems/dp/1491950358)

timeout/etc/timeout.urm.png.png

31.9 KB
Loading

timeout/etc/timeout.urm.puml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@startuml
2+
package com.iluwatar.timeout {
3+
4+
class TimeoutException {
5+
+ TimeoutException(message: String)
6+
+ TimeoutException(message: String, cause: Throwable)
7+
}
8+
9+
class TimeoutHandler {
10+
- executor: ExecutorService
11+
+ TimeoutHandler()
12+
+ execute(task: Callable<T>, timeout: long, unit: TimeUnit): T
13+
+ shutdown(): void
14+
}
15+
16+
class App {
17+
+ {static} main(args: String[]): void
18+
}
19+
20+
TimeoutHandler ..> TimeoutException : throws
21+
App ..> TimeoutHandler : uses
22+
App ..> TimeoutException : catches
23+
}
24+
25+
note right of TimeoutHandler
26+
Executes tasks with timeout constraints.
27+
Uses ExecutorService to run tasks
28+
asynchronously and enforce time limits.
29+
end note
30+
31+
note right of TimeoutException
32+
Custom exception thrown when
33+
an operation exceeds its
34+
timeout duration.
35+
end note
36+
37+
@enduml

timeout/pom.xml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>com.iluwatar</groupId>
9+
<artifactId>java-design-patterns</artifactId>
10+
<version>1.26.0-SNAPSHOT</version>
11+
</parent>
12+
13+
<artifactId>timeout</artifactId>
14+
<packaging>jar</packaging>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>org.projectlombok</groupId>
19+
<artifactId>lombok</artifactId>
20+
</dependency>
21+
<dependency>
22+
<groupId>ch.qos.logback</groupId>
23+
<artifactId>logback-classic</artifactId>
24+
</dependency>
25+
<dependency>
26+
<groupId>org.junit.jupiter</groupId>
27+
<artifactId>junit-jupiter-engine</artifactId>
28+
<scope>test</scope>
29+
</dependency>
30+
</dependencies>
31+
32+
</project>

0 commit comments

Comments
 (0)