Skip to content

Commit ab93819

Browse files
committed
Issue ReactiveX#531: Refactored TimeLimiter to emit Events.
1 parent 6be60e8 commit ab93819

File tree

9 files changed

+86
-46
lines changed

9 files changed

+86
-46
lines changed

resilience4j-circuitbreaker/src/main/java/io/github/resilience4j/circuitbreaker/internal/CircuitBreakerStateMachine.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public void acquirePermission() {
152152

153153
@Override
154154
public void onError(long duration, TimeUnit durationUnit, Throwable throwable) {
155-
// Handle the case if the completable future throw CompletionException wrapping the original exception
155+
// Handle the case if the completable future throws a CompletionException wrapping the original exception
156156
// where original exception is the the one to retry not the CompletionException.
157157
if (throwable instanceof CompletionException) {
158158
Throwable cause = throwable.getCause();
@@ -278,9 +278,9 @@ private boolean shouldPublishEvents(CircuitBreakerEvent event) {
278278
private void publishEventIfPossible(CircuitBreakerEvent event) {
279279
if(shouldPublishEvents(event)) {
280280
if (eventProcessor.hasConsumers()) {
281-
LOG.debug("Event {} published: {}", event.getEventType(), event);
282281
try{
283282
eventProcessor.consumeEvent(event);
283+
LOG.debug("Event {} published: {}", event.getEventType(), event);
284284
}catch (Throwable t){
285285
LOG.warn("Failed to handle event {}", event.getEventType(), t);
286286
}

resilience4j-timelimiter/src/main/java/io/github/resilience4j/timelimiter/TimeLimiter.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import io.github.resilience4j.core.EventConsumer;
44
import io.github.resilience4j.timelimiter.event.TimeLimiterEvent;
5-
import io.github.resilience4j.timelimiter.event.TimeLimiterOnFailureEvent;
5+
import io.github.resilience4j.timelimiter.event.TimeLimiterOnErrorEvent;
66
import io.github.resilience4j.timelimiter.event.TimeLimiterOnSuccessEvent;
77
import io.github.resilience4j.timelimiter.event.TimeLimiterOnTimeoutEvent;
88
import io.github.resilience4j.timelimiter.internal.TimeLimiterImpl;
@@ -107,9 +107,19 @@ default <T, F extends Future<T>> T executeFutureSupplier(Supplier<F> futureSuppl
107107

108108
EventPublisher getEventPublisher();
109109

110+
/**
111+
* Records a successful call.
112+
*
113+
* This method must be invoked when a call was successful.
114+
*/
110115
void onSuccess();
111116

112-
void onError(Exception exception);
117+
/**
118+
* Records a failed call.
119+
* This method must be invoked when a call failed.
120+
* @param throwable The throwable which must be recorded
121+
*/
122+
void onError(Throwable throwable);
113123

114124
/**
115125
* An EventPublisher which can be used to register event consumers.
@@ -118,7 +128,7 @@ interface EventPublisher extends io.github.resilience4j.core.EventPublisher<Time
118128

119129
EventPublisher onSuccess(EventConsumer<TimeLimiterOnSuccessEvent> eventConsumer);
120130

121-
EventPublisher onFailure(EventConsumer<TimeLimiterOnFailureEvent> eventConsumer);
131+
EventPublisher onError(EventConsumer<TimeLimiterOnErrorEvent> eventConsumer);
122132

123133
EventPublisher onTimeout(EventConsumer<TimeLimiterOnTimeoutEvent> eventConsumer);
124134

resilience4j-timelimiter/src/main/java/io/github/resilience4j/timelimiter/event/TimeLimiterEvent.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,6 @@
2525
*/
2626
public interface TimeLimiterEvent {
2727

28-
static TimeLimiterEvent of(String name, Type eventType) {
29-
switch (eventType) {
30-
case SUCCESS:
31-
return new TimeLimiterOnSuccessEvent(name);
32-
case TIMEOUT:
33-
return new TimeLimiterOnTimeoutEvent(name);
34-
default:
35-
return new TimeLimiterOnFailureEvent(name);
36-
}
37-
}
38-
3928
String getTimeLimiterName();
4029

4130
Type getEventType();
@@ -45,6 +34,6 @@ static TimeLimiterEvent of(String name, Type eventType) {
4534
enum Type {
4635
SUCCESS,
4736
TIMEOUT,
48-
FAILURE
37+
ERROR
4938
}
5039
}
Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,25 @@
1818
*/
1919
package io.github.resilience4j.timelimiter.event;
2020

21-
public class TimeLimiterOnFailureEvent extends AbstractTimeLimiterEvent {
21+
public class TimeLimiterOnErrorEvent extends AbstractTimeLimiterEvent {
2222

23-
public TimeLimiterOnFailureEvent(String timeLimiterName) {
24-
super(timeLimiterName, Type.FAILURE);
23+
private final Throwable throwable;
24+
25+
public TimeLimiterOnErrorEvent(String timeLimiterName, Throwable throwable) {
26+
super(timeLimiterName, Type.ERROR);
27+
this.throwable = throwable;
28+
}
29+
30+
public Throwable getThrowable() {
31+
return throwable;
32+
}
33+
34+
@Override
35+
public String toString() {
36+
return String.format("%s: TimeLimiter '%s' recorded an error: '%s'",
37+
getCreationTime(),
38+
getTimeLimiterName(),
39+
getThrowable().toString());
2540
}
2641

2742
}

resilience4j-timelimiter/src/main/java/io/github/resilience4j/timelimiter/event/TimeLimiterOnSuccessEvent.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,11 @@ public TimeLimiterOnSuccessEvent(String timeLimiterName) {
2424
super(timeLimiterName, Type.SUCCESS);
2525
}
2626

27+
@Override
28+
public String toString() {
29+
return String.format("%s: TimeLimiter '%s' recorded a successful call.",
30+
getCreationTime(),
31+
getTimeLimiterName());
32+
}
33+
2734
}

resilience4j-timelimiter/src/main/java/io/github/resilience4j/timelimiter/event/TimeLimiterOnTimeoutEvent.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,11 @@ public TimeLimiterOnTimeoutEvent(String timeLimiterName) {
2424
super(timeLimiterName, Type.TIMEOUT);
2525
}
2626

27+
@Override
28+
public String toString() {
29+
return String.format("%s: TimeLimiter '%s' recorded a timeout exception.",
30+
getCreationTime(),
31+
getTimeLimiterName());
32+
}
33+
2734
}

resilience4j-timelimiter/src/main/java/io/github/resilience4j/timelimiter/internal/TimeLimiterEventProcessor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import io.github.resilience4j.core.EventProcessor;
2424
import io.github.resilience4j.timelimiter.TimeLimiter;
2525
import io.github.resilience4j.timelimiter.event.TimeLimiterEvent;
26-
import io.github.resilience4j.timelimiter.event.TimeLimiterOnFailureEvent;
26+
import io.github.resilience4j.timelimiter.event.TimeLimiterOnErrorEvent;
2727
import io.github.resilience4j.timelimiter.event.TimeLimiterOnSuccessEvent;
2828
import io.github.resilience4j.timelimiter.event.TimeLimiterOnTimeoutEvent;
2929

@@ -41,8 +41,8 @@ public TimeLimiter.EventPublisher onSuccess(EventConsumer<TimeLimiterOnSuccessEv
4141
}
4242

4343
@Override
44-
public TimeLimiter.EventPublisher onFailure(EventConsumer<TimeLimiterOnFailureEvent> onOnFailureEventConsumer) {
45-
registerConsumer(TimeLimiterOnFailureEvent.class.getSimpleName(), onOnFailureEventConsumer);
44+
public TimeLimiter.EventPublisher onError(EventConsumer<TimeLimiterOnErrorEvent> onOnFailureEventConsumer) {
45+
registerConsumer(TimeLimiterOnErrorEvent.class.getSimpleName(), onOnFailureEventConsumer);
4646
return this;
4747
}
4848

resilience4j-timelimiter/src/main/java/io/github/resilience4j/timelimiter/internal/TimeLimiterImpl.java

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
import io.github.resilience4j.timelimiter.TimeLimiter;
44
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
55
import io.github.resilience4j.timelimiter.event.TimeLimiterEvent;
6+
import io.github.resilience4j.timelimiter.event.TimeLimiterOnErrorEvent;
7+
import io.github.resilience4j.timelimiter.event.TimeLimiterOnSuccessEvent;
8+
import io.github.resilience4j.timelimiter.event.TimeLimiterOnTimeoutEvent;
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
611

712
import java.util.concurrent.Callable;
813
import java.util.concurrent.ExecutionException;
@@ -13,6 +18,8 @@
1318

1419
public class TimeLimiterImpl implements TimeLimiter {
1520

21+
private static final Logger LOG = LoggerFactory.getLogger(TimeLimiterImpl.class);
22+
1623
private String name;
1724
private final TimeLimiterConfig timeLimiterConfig;
1825
private final TimeLimiterEventProcessor eventProcessor;
@@ -38,11 +45,12 @@ public <T, F extends Future<T>> Callable<T> decorateFutureSupplier(Supplier<F> f
3845
}
3946
throw e;
4047
} catch (ExecutionException e) {
41-
onError(e);
4248
Throwable t = e.getCause();
4349
if (t == null) {
50+
onError(e);
4451
throw e;
4552
}
53+
onError(t);
4654
if (t instanceof Error) {
4755
throw (Error) t;
4856
}
@@ -51,14 +59,6 @@ public <T, F extends Future<T>> Callable<T> decorateFutureSupplier(Supplier<F> f
5159
};
5260
}
5361

54-
private void publishTimeLimiterEvent(TimeLimiterEvent.Type eventType) {
55-
if (!eventProcessor.hasConsumers()) {
56-
return;
57-
}
58-
eventProcessor.consumeEvent(TimeLimiterEvent.of(name, eventType));
59-
60-
}
61-
6262
@Override
6363
public TimeLimiterConfig getTimeLimiterConfig() {
6464
return timeLimiterConfig;
@@ -71,15 +71,30 @@ public EventPublisher getEventPublisher() {
7171

7272
@Override
7373
public void onSuccess() {
74-
publishTimeLimiterEvent(TimeLimiterEvent.Type.SUCCESS);
74+
if (!eventProcessor.hasConsumers()) {
75+
return;
76+
}
77+
publishEvent(new TimeLimiterOnSuccessEvent(name));
7578
}
7679

7780
@Override
78-
public void onError(Exception e) {
79-
if (e instanceof TimeoutException) {
80-
publishTimeLimiterEvent(TimeLimiterEvent.Type.TIMEOUT);
81+
public void onError(Throwable throwable) {
82+
if (!eventProcessor.hasConsumers()) {
83+
return;
84+
}
85+
if (throwable instanceof TimeoutException) {
86+
publishEvent(new TimeLimiterOnTimeoutEvent(name));
8187
} else {
82-
publishTimeLimiterEvent(TimeLimiterEvent.Type.FAILURE);
88+
publishEvent(new TimeLimiterOnErrorEvent(name, throwable));
89+
}
90+
}
91+
92+
private void publishEvent(TimeLimiterEvent event) {
93+
try{
94+
eventProcessor.consumeEvent(event);
95+
LOG.debug("Event {} published: {}", event.getEventType(), event);
96+
}catch (Throwable t){
97+
LOG.warn("Failed to handle event {}", event.getEventType(), t);
8398
}
8499
}
85100

resilience4j-timelimiter/src/test/java/io/github/resilience4j/timelimiter/TimeLimiterEventPublisherTest.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package io.github.resilience4j.timelimiter;
2020

2121
import io.github.resilience4j.timelimiter.event.TimeLimiterEvent;
22+
import io.github.resilience4j.timelimiter.event.TimeLimiterOnErrorEvent;
2223
import io.vavr.control.Try;
2324

2425
import java.time.Duration;
@@ -54,7 +55,7 @@ public void shouldReturnTheSameConsumer() {
5455
public void shouldConsumeOnSuccessEvent() throws Exception {
5556
TimeLimiter timeLimiter = TimeLimiter.of(NEVER);
5657
timeLimiter.getEventPublisher()
57-
.onSuccess(this::logEventType);
58+
.onSuccess(event -> logger.info(event.getEventType().toString()));
5859
Supplier<CompletableFuture<String>> futureSupplier = () ->
5960
CompletableFuture.completedFuture("Hello world");
6061

@@ -68,7 +69,7 @@ public void shouldConsumeOnSuccessEvent() throws Exception {
6869
public void shouldConsumeOnTimeoutEvent() {
6970
TimeLimiter timeLimiter = TimeLimiter.of(NEVER);
7071
timeLimiter.getEventPublisher()
71-
.onTimeout(this::logEventType);
72+
.onTimeout(event -> logger.info(event.getEventType().toString()));
7273
Supplier<CompletableFuture<String>> futureSupplier = () ->
7374
CompletableFuture.supplyAsync(this::fail);
7475

@@ -78,20 +79,16 @@ public void shouldConsumeOnTimeoutEvent() {
7879
}
7980

8081
@Test
81-
public void shouldConsumeOnFailureEvent() {
82+
public void shouldConsumeOnErrorEvent() {
8283
TimeLimiter timeLimiter = TimeLimiter.of(Duration.ofSeconds(1));
8384
timeLimiter.getEventPublisher()
84-
.onFailure(this::logEventType);
85+
.onError(event -> logger.info(event.getEventType().toString() + " " + event.getThrowable().toString()));
8586
Supplier<CompletableFuture<String>> futureSupplier = () ->
8687
CompletableFuture.supplyAsync(this::fail);
8788

8889
Try.ofCallable(timeLimiter.decorateFutureSupplier(futureSupplier));
8990

90-
then(logger).should(times(1)).info("FAILURE");
91-
}
92-
93-
private void logEventType(TimeLimiterEvent event) {
94-
logger.info(event.getEventType().toString());
91+
then(logger).should(times(1)).info("ERROR java.lang.RuntimeException");
9592
}
9693

9794
private String fail() {

0 commit comments

Comments
 (0)