Skip to content

Commit 21357ee

Browse files
authored
fix: status update trigger (#2719) (#2760)
(cherry picked from commit 521b43c)
1 parent 568d102 commit 21357ee

File tree

5 files changed

+36
-33
lines changed

5 files changed

+36
-33
lines changed

spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/services/AbstractEventHandler.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import reactor.core.publisher.Flux;
2828
import reactor.core.scheduler.Scheduler;
2929
import reactor.core.scheduler.Schedulers;
30-
import reactor.util.retry.Retry;
3130

3231
import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
3332

@@ -55,8 +54,7 @@ public void start() {
5554
this.subscription = Flux.from(this.publisher).subscribeOn(this.scheduler).log(this.log.getName(), Level.FINEST)
5655
.doOnSubscribe((s) -> this.log.debug("Subscribed to {} events", this.eventType)).ofType(this.eventType)
5756
.cast(this.eventType).transform(this::handle)
58-
.retryWhen(Retry.indefinitely().doBeforeRetry((s) -> this.log.warn("Unexpected error", s.failure())))
59-
.subscribe();
57+
.onErrorContinue((throwable, o) -> this.log.warn("Unexpected error", throwable)).subscribe();
6058
}
6159

6260
protected abstract Publisher<Void> handle(Flux<T> publisher);

spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/services/IntervalCheck.java

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@
2525

2626
import javax.annotation.Nullable;
2727

28-
import org.slf4j.Logger;
29-
import org.slf4j.LoggerFactory;
28+
import lombok.Getter;
29+
import lombok.Setter;
30+
import lombok.extern.slf4j.Slf4j;
3031
import reactor.core.Disposable;
3132
import reactor.core.publisher.Flux;
3233
import reactor.core.publisher.Mono;
@@ -43,18 +44,20 @@
4344
*
4445
* @author Johannes Edmeier
4546
*/
47+
@Slf4j
4648
public class IntervalCheck {
4749

48-
private static final Logger log = LoggerFactory.getLogger(IntervalCheck.class);
49-
5050
private final String name;
5151

5252
private final Map<InstanceId, Instant> lastChecked = new ConcurrentHashMap<>();
5353

5454
private final Function<InstanceId, Mono<Void>> checkFn;
5555

56+
@Getter
57+
@Setter
5658
private Duration interval;
5759

60+
@Setter
5861
private Duration minRetention;
5962

6063
@Nullable
@@ -82,7 +85,7 @@ public void start() {
8285
.log(log.getName(), Level.FINEST).subscribeOn(this.scheduler).concatMap((i) -> this.checkAllInstances())
8386
.retryWhen(Retry.indefinitely()
8487
.doBeforeRetry((s) -> log.warn("Unexpected error in {}-check", this.name, s.failure())))
85-
.subscribe();
88+
.subscribe(null, (error) -> log.error("Unexpected error in {}-check", name, error));
8689
}
8790

8891
public void markAsChecked(InstanceId instanceId) {
@@ -92,7 +95,7 @@ public void markAsChecked(InstanceId instanceId) {
9295
protected Mono<Void> checkAllInstances() {
9396
log.debug("check {} for all instances", this.name);
9497
Instant expiration = Instant.now().minus(this.minRetention);
95-
return Flux.fromIterable(this.lastChecked.entrySet()).filter((e) -> e.getValue().isBefore(expiration))
98+
return Flux.fromIterable(this.lastChecked.entrySet()).filter((entry) -> entry.getValue().isBefore(expiration))
9699
.map(Map.Entry::getKey).flatMap(this.checkFn).then();
97100
}
98101

@@ -107,12 +110,4 @@ public void stop() {
107110
}
108111
}
109112

110-
public void setInterval(Duration interval) {
111-
this.interval = interval;
112-
}
113-
114-
public void setMinRetention(Duration minRetention) {
115-
this.minRetention = minRetention;
116-
}
117-
118113
}

spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/services/StatusUpdateTrigger.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,11 @@ protected Publisher<Void> handle(Flux<InstanceEvent> publisher) {
5252
}
5353

5454
protected Mono<Void> updateStatus(InstanceId instanceId) {
55-
return this.statusUpdater.updateStatus(instanceId).onErrorResume((e) -> {
56-
log.warn("Unexpected error while updating status for {}", instanceId, e);
57-
return Mono.empty();
58-
}).doFinally((s) -> this.intervalCheck.markAsChecked(instanceId));
55+
return this.statusUpdater.timeout(this.intervalCheck.getInterval()).updateStatus(instanceId)
56+
.onErrorResume((e) -> {
57+
log.warn("Unexpected error while updating status for {}", instanceId, e);
58+
return Mono.empty();
59+
}).doFinally((s) -> this.intervalCheck.markAsChecked(instanceId));
5960
}
6061

6162
@Override

spring-boot-admin-server/src/main/java/de/codecentric/boot/admin/server/services/StatusUpdater.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616

1717
package de.codecentric.boot.admin.server.services;
1818

19+
import java.time.Duration;
1920
import java.util.HashMap;
2021
import java.util.LinkedHashMap;
2122
import java.util.Map;
2223
import java.util.logging.Level;
2324

24-
import org.slf4j.Logger;
25-
import org.slf4j.LoggerFactory;
25+
import lombok.RequiredArgsConstructor;
26+
import lombok.extern.slf4j.Slf4j;
2627
import org.springframework.core.ParameterizedTypeReference;
2728
import org.springframework.http.HttpStatus;
2829
import org.springframework.http.MediaType;
@@ -44,10 +45,10 @@
4445
*
4546
* @author Johannes Edmeier
4647
*/
48+
@Slf4j
49+
@RequiredArgsConstructor
4750
public class StatusUpdater {
4851

49-
private static final Logger log = LoggerFactory.getLogger(StatusUpdater.class);
50-
5152
private static final ParameterizedTypeReference<Map<String, Object>> RESPONSE_TYPE = new ParameterizedTypeReference<Map<String, Object>>() {
5253
};
5354

@@ -57,16 +58,15 @@ public class StatusUpdater {
5758

5859
private final ApiMediaTypeHandler apiMediaTypeHandler;
5960

60-
public StatusUpdater(InstanceRepository repository, InstanceWebClient instanceWebClient,
61-
ApiMediaTypeHandler apiMediaTypeHandler) {
62-
this.repository = repository;
63-
this.instanceWebClient = instanceWebClient;
64-
this.apiMediaTypeHandler = apiMediaTypeHandler;
61+
private Duration timeout = Duration.ofSeconds(10);
62+
63+
public StatusUpdater timeout(Duration timeout) {
64+
this.timeout = timeout;
65+
return this;
6566
}
6667

6768
public Mono<Void> updateStatus(InstanceId id) {
6869
return this.repository.computeIfPresent(id, (key, instance) -> this.doUpdateStatus(instance)).then();
69-
7070
}
7171

7272
protected Mono<Instance> doUpdateStatus(Instance instance) {
@@ -77,8 +77,16 @@ protected Mono<Instance> doUpdateStatus(Instance instance) {
7777
log.debug("Update status for {}", instance);
7878
return this.instanceWebClient.instance(instance).get().uri(Endpoint.HEALTH)
7979
.exchangeToMono(this::convertStatusInfo).log(log.getName(), Level.FINEST)
80-
.doOnError((ex) -> logError(instance, ex)).onErrorResume(this::handleError)
81-
.map(instance::withStatusInfo);
80+
.timeout(getTimeoutWithMargin()).doOnError((ex) -> logError(instance, ex))
81+
.onErrorResume(this::handleError).map(instance::withStatusInfo);
82+
}
83+
84+
/*
85+
* return a timeout less than the given one to prevent backdrops in concurrent get
86+
* request. This prevents flakyness of health checks.
87+
*/
88+
private Duration getTimeoutWithMargin() {
89+
return this.timeout.minusSeconds(1).abs();
8290
}
8391

8492
protected Mono<StatusInfo> convertStatusInfo(ClientResponse response) {

spring-boot-admin-server/src/test/java/de/codecentric/boot/admin/server/services/StatusUpdateTriggerTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public class StatusUpdateTriggerTest {
5656
@BeforeEach
5757
public void setUp() throws Exception {
5858
when(this.updater.updateStatus(any(InstanceId.class))).thenReturn(Mono.empty());
59+
when(this.updater.timeout(any())).thenReturn(this.updater);
5960

6061
this.trigger = new StatusUpdateTrigger(this.updater, this.events.flux());
6162
this.trigger.start();

0 commit comments

Comments
 (0)