Skip to content

Commit 4e0801b

Browse files
committed
iluwatar#1627 adding programmatic examples in README.md
1 parent 1948342 commit 4e0801b

File tree

1 file changed

+85
-8
lines changed

1 file changed

+85
-8
lines changed

fanout-fanin/README.md

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,108 @@ tags:
1010
---
1111

1212
## Intent
13-
The pattern is used when a source system needs to run one or more long-running process that will fetch some data.
14-
Source will not block itself waiting for the reply. <br> The pattern will run the same function in multiple
13+
The pattern is used when a source system needs to run one or more long-running processes that will fetch some data.
14+
The source will not block itself waiting for the reply. <br> The pattern will run the same function in multiple
1515
services or machines to fetch the data. This is equivalent to invoking the function multiple times on different chunks of data.
1616

1717
## Explanation
18-
The FanOut/FanIn service will take in a list of requests and a consumer. Each request might complete at different time.
18+
The FanOut/FanIn service will take in a list of requests and a consumer. Each request might complete at a different time.
1919
FanOut/FanIn service will accept the input params and returns the initial system an ID to acknowledge that the pattern
2020
service has received the requests. Now the caller will not wait or expect the result in the same connection.
2121

2222
Meanwhile, the pattern service will invoke the requests that have come. The requests might complete at different time.
2323
These requests will be processed in different instances of the same function in different machines or services. As the
24-
requests get completed, a callback service everytime is called that transforms the result into a common format, or a single object
25-
that gets pushed to a consumer. That caller will be at the other end of the consumer receiving the result.
24+
requests get completed, a callback service everytime is called that transforms the result into a common single object format
25+
that gets pushed to a consumer. The caller will be at the other end of the consumer receiving the result.
26+
27+
**Programmatic Example**
28+
29+
The implementation provided has a list of numbers and end goal is to square the numbers and add them to a single result.
30+
`FanOutFanIn` class receives the list of numbers in the form of list of `SquareNumberRequest` and a `Consumer` instance
31+
that collects the results as the requests get over. `SquareNumberRequest` will square the number with a random delay
32+
to give the impression of a long-running process that can complete at any time. `Consumer` instance will add the results from
33+
different `SquareNumberRequest` that will come random time instances.
34+
35+
Let's look at `FanOutFanIn` class that fans out the requests in async processes.
36+
37+
```java
38+
public class FanOutFanIn {
39+
public static Long fanOutFanIn(
40+
final List<SquareNumberRequest> requests, final Consumer consumer) {
41+
42+
ExecutorService service = Executors.newFixedThreadPool(requests.size());
43+
44+
// fanning out
45+
List<CompletableFuture<Void>> futures =
46+
requests.stream()
47+
.map(
48+
request ->
49+
CompletableFuture.runAsync(() -> request.delayedSquaring(consumer), service))
50+
.collect(Collectors.toList());
51+
52+
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
53+
54+
return consumer.getSumOfSquaredNumbers().get();
55+
}
56+
}
57+
```
58+
59+
`Consumer` is used a callback class that will be called when a request is completed. This will aggregate
60+
the result from all requests.
61+
62+
```java
63+
public class Consumer {
64+
65+
private final AtomicLong sumOfSquaredNumbers;
66+
67+
Consumer(Long init) {
68+
sumOfSquaredNumbers = new AtomicLong(init);
69+
}
70+
71+
public Long add(final Long num) {
72+
return sumOfSquaredNumbers.addAndGet(num);
73+
}
74+
}
75+
```
76+
77+
Request is represented as a `SquareNumberRequest` that squares the number with random delay and calls the
78+
`Consumer` once it is squared.
79+
80+
```java
81+
public class SquareNumberRequest {
82+
83+
private final Long number;
84+
public void delayedSquaring(final Consumer consumer) {
85+
86+
var minTimeOut = 5000L;
87+
88+
SecureRandom secureRandom = new SecureRandom();
89+
var randomTimeOut = secureRandom.nextInt(2000);
90+
91+
try {
92+
// this will make the thread sleep from 5-7s.
93+
Thread.sleep(minTimeOut + randomTimeOut);
94+
} catch (InterruptedException e) {
95+
LOGGER.error("Exception while sleep ", e);
96+
Thread.currentThread().interrupt();
97+
} finally {
98+
consumer.add(number * number);
99+
}
100+
}
101+
}
102+
```
26103

27104
## Class diagram
28105
![alt-text](./etc/fanout-fanin.png)
29106

30107
## Applicability
31108

32-
Use this pattern when you can chunk the workload or load into multiple chunks that can be dealt with separately.
109+
Use this pattern when you can divide the workload into multiple chunks that can be dealt with separately.
33110

34111
## Related patterns
35112

36-
- Aggregator Microservices
37-
- API Gateway
113+
* [Aggregator Microservices](https://java-design-patterns.com/patterns/aggregator-microservices/)
114+
* [API Gateway](https://java-design-patterns.com/patterns/api-gateway/)
38115

39116
## Credits
40117

0 commit comments

Comments
 (0)