【发布时间】:2021-09-12 13:46:39
【问题描述】:
在我的 Spring Boot 应用程序中,我有一个组件应该监控另一个外部系统的健康状态。该组件还提供了一个公共方法,反应链可以订阅以等待外部系统启动。
@Component
public class ExternalHealthChecker {
private static final Logger LOG = LoggerFactory.getLogger(ExternalHealthChecker.class);
private final WebClient externalSystemWebClient = WebClient.builder().build(); // config omitted
private volatile boolean isUp = true;
private volatile CompletableFuture<String> completeWhenUp = new CompletableFuture<>();
@Scheduled(cron = "0/10 * * ? * *")
private void checkExternalSystemHealth() {
webClient.get() //
.uri("/health") //
.retrieve() //
.bodyToMono(Void.class) //
.doOnError(this::handleHealthCheckError) //
.doOnSuccess(nothing -> this.handleHealthCheckSuccess()) //
.subscribe(); //
}
private void handleHealthCheckError(final Throwable error) {
if (this.isUp) {
LOG.error("External System is now DOWN. Health check failed: {}.", error.getMessage());
}
this.isUp = false;
}
private void handleHealthCheckSuccess() {
// the status changed from down -> up, which has to complete the future that might be currently waited on
if (!this.isUp) {
LOG.warn("External System is now UP again.");
this.isUp = true;
this.completeWhenUp.complete("UP");
this.completeWhenUp = new CompletableFuture<>();
}
}
public Mono<String> waitForExternalSystemUPStatus() {
if (this.isUp) {
LOG.info("External System is already UP!");
return Mono.empty();
} else {
LOG.warn("External System is DOWN. Requesting process can now wait for UP status!");
return Mono.fromFuture(completeWhenUp);
}
}
}
waitForExternalSystemUPStatus 方法是公共的,可以从许多不同的线程调用。这背后的想法是为应用程序中的一些反应通量链提供一种暂停其处理直到外部系统启动的方法。当外部系统宕机时,这些链无法处理它们的元素。
someFlux
.doOnNext(record -> LOG.info("Next element")
.delayUntil(record -> externalHealthChecker.waitForExternalSystemUPStatus())
... // starting processing
这里的问题是我无法真正理解这段代码的哪一部分需要同步。我认为多个线程同时调用waitForExternalSystemUPStatus不应该有问题,因为这种方法没有写任何东西。所以我觉得这个方法不需要同步。但是,带有@Scheduled 注释的方法也将在它自己的线程上运行,并且实际上会写入isUp 的值,并且还可能将completeWhenUp 的引用更改为新的未完成的未来实例。我已经用volatile标记了这两个可变属性,因为在阅读Java 中的这个关键字后,我觉得它有助于确保读取这两个值的线程看到最新的值。但是,我不确定是否还需要在部分代码中添加 synchronized 关键字。我也不确定 synchronized 关键字是否与反应器代码配合得很好,我很难找到这方面的信息。也许还有一种方法可以以更完整、更被动的方式提供ExternalHealthChecker 的功能,但我想不出任何方法。
【问题讨论】:
标签: java spring-boot spring-webflux project-reactor