You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Another concern is the impact on the calling code by implementing the retry mechanism. The retry
28
+
mechanics should ideally be completely transparent to the calling code (service interface remains
29
+
unaltered). There are two general approaches to this problem: From an enterprise architecture
30
+
standpoint (strategic), and a shared library standpoint (tactical).
31
+
32
+
From a strategic point of view, this would be solved by having requests redirected to a separate
33
+
intermediary system, traditionally an [ESB](https://en.wikipedia.org/wiki/Enterprise_service_bus),
34
+
but more recently a [Service Mesh](https://medium.com/microservices-in-practice/service-mesh-for-microservices-2953109a3c9a).
35
+
36
+
From a tactical point of view, this would be solved by reusing shared libraries like
37
+
[Hystrix](https://github.com/Netflix/Hystrix) (please note that Hystrix is a complete implementation
38
+
of the [Circuit Breaker](https://java-design-patterns.com/patterns/circuit-breaker/) pattern, of
39
+
which the Retry pattern can be considered a subset of). This is the type of solution showcased in
40
+
the simple example that accompanies this `README.md`.
42
41
43
42
Real world example
44
43
45
-
> Our application uses a service providing customer information. Once in a while the service seems to be flaky and can return errors or sometimes it just times out. To circumvent these problems we apply the retry pattern.
44
+
> Our application uses a service providing customer information. Once in a while the service seems
45
+
> to be flaky and can return errors or sometimes it just times out. To circumvent these problems we
46
+
> apply the retry pattern.
46
47
47
48
In plain words
48
49
49
50
> Retry pattern transparently retries failed operations over network.
> Enable an application to handle transient failures when it tries to connect to a service or network resource, by transparently retrying a failed operation. This can improve the stability of the application.
54
+
> Enable an application to handle transient failures when it tries to connect to a service or
55
+
> network resource, by transparently retrying a failed operation. This can improve the stability of
56
+
> the application.
54
57
55
58
**Programmatic Example**
56
59
57
-
In our hypothetical application, we have a generic interface for all operations on remote interfaces.
60
+
In our hypothetical application, we have a generic interface for all operations on remote
61
+
interfaces.
58
62
59
63
```java
60
64
publicinterfaceBusinessOperation<T> {
@@ -73,16 +77,14 @@ public final class FindCustomer implements BusinessOperation<String> {
73
77
}
74
78
```
75
79
76
-
Our `FindCustomer` implementation can be configured to throw
77
-
`BusinessException`s before returning the customer's ID, thereby simulating a
78
-
'flaky' service that intermittently fails. Some exceptions, like the
79
-
`CustomerNotFoundException`, are deemed to be recoverable after some
80
-
hypothetical analysis because the root cause of the error stems from "some
81
-
database locking issue". However, the `DatabaseNotAvailableException` is
82
-
considered to be a definite showstopper - the application should not attempt
83
-
to recover from this error.
80
+
Our `FindCustomer` implementation can be configured to throw `BusinessException`s before returning
81
+
the customer's ID, thereby simulating a flaky service that intermittently fails. Some exceptions,
82
+
like the `CustomerNotFoundException`, are deemed to be recoverable after some hypothetical analysis
83
+
because the root cause of the error stems from "some database locking issue". However, the
84
+
`DatabaseNotAvailableException` is considered to be a definite showstopper - the application should
85
+
not attempt to recover from this error.
84
86
85
-
We can model a 'recoverable' scenario by instantiating `FindCustomer` like this:
87
+
We can model a recoverable scenario by instantiating `FindCustomer` like this:
86
88
87
89
```java
88
90
finalvar op =newFindCustomer(
@@ -93,15 +95,12 @@ final var op = new FindCustomer(
93
95
);
94
96
```
95
97
96
-
In this configuration, `FindCustomer` will throw `CustomerNotFoundException`
97
-
three times, after which it will consistently return the customer's ID
98
-
(`12345`).
98
+
In this configuration, `FindCustomer` will throw `CustomerNotFoundException` three times, after
99
+
which it will consistently return the customer's ID (`12345`).
99
100
100
-
In our hypothetical scenario, our analysts indicate that this operation
101
-
typically fails 2-4 times for a given input during peak hours, and that each
102
-
worker thread in the database subsystem typically needs 50ms to
103
-
"recover from an error". Applying these policies would yield something like
104
-
this:
101
+
In our hypothetical scenario, our analysts indicate that this operation typically fails 2-4 times
102
+
for a given input during peak hours, and that each worker thread in the database subsystem typically
103
+
needs 50ms to "recover from an error". Applying these policies would yield something like this:
105
104
106
105
```java
107
106
finalvar op =newRetry<>(
@@ -117,26 +116,27 @@ final var op = new Retry<>(
117
116
);
118
117
```
119
118
120
-
Executing `op`*once* would automatically trigger at most 5 retry attempts,
121
-
with a 100 millisecond delay between attempts, ignoring any
122
-
`CustomerNotFoundException` thrown while trying. In this particular scenario,
123
-
due to the configuration for `FindCustomer`, there will be 1 initial attempt
119
+
Executing `op` once would automatically trigger at most 5 retry attempts, with a 100 millisecond
120
+
delay between attempts, ignoring any `CustomerNotFoundException` thrown while trying. In this
121
+
particular scenario, due to the configuration for `FindCustomer`, there will be 1 initial attempt
124
122
and 3 additional retries before finally returning the desired result `12345`.
125
123
126
-
If our `FindCustomer` operation were instead to throw a fatal
127
-
`DatabaseNotFoundException`, which we were instructed not to ignore, but
128
-
more importantly we did *not* instruct our `Retry` to ignore, then the operation
129
-
would have failed immediately upon receiving the error, not matter how many
130
-
attempts were left.
124
+
If our `FindCustomer` operation were instead to throw a fatal `DatabaseNotFoundException`, which we
125
+
were instructed not to ignore, but more importantly we did not instruct our `Retry` to ignore, then
126
+
the operation would have failed immediately upon receiving the error, not matter how many attempts
127
+
were left.
131
128
132
129
## Class diagram
130
+
133
131

134
132
135
133
## Applicability
136
-
Whenever an application needs to communicate with an external resource, particularly in a cloud environment, and if
137
-
the business requirements allow it.
134
+
135
+
Whenever an application needs to communicate with an external resource, particularly in a cloud
136
+
environment, and if the business requirements allow it.
0 commit comments