Created
December 15, 2021 01:26
-
-
Save srbs/fc2daa1491d80b2dd30b5ec824f3c010 to your computer and use it in GitHub Desktop.
spring-boot-admin auto-deregister scheduled task when a replacement is online
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import de.codecentric.boot.admin.server.domain.entities.Instance; | |
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository; | |
import de.codecentric.boot.admin.server.domain.values.InstanceId; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import reactor.core.publisher.Mono; | |
// inspired by: https://github.com/codecentric/spring-boot-admin/issues/535#issuecomment-493010425 | |
// behaves similar to InfoUpdate, but _only_ deregisters when a replacement is online | |
public class DeregisterOffline { | |
private static final Logger log = LoggerFactory.getLogger(DeregisterOffline.class); | |
private final InstanceRepository repository; | |
public DeregisterOffline(InstanceRepository repository) { | |
this.repository = repository; | |
} | |
public Mono<Void> deregisterCheck(InstanceId id) { | |
return repository.computeIfPresent(id, (key, instance) -> this.doDeregisterCheck(instance)).then(); | |
} | |
private Mono<Instance> doDeregisterCheck(Instance instance) { | |
// only check those that are offline | |
if (!instance.getStatusInfo().isOffline()) { | |
return Mono.empty(); | |
} | |
// look for instances with the same name | |
return repository.findByName(instance.getRegistration().getName()) | |
// are any online? | |
.any(it -> !it.getStatusInfo().isOffline()) | |
// if so, deregister given offline instance | |
.map(result -> result ? this.deregister(instance) : instance); | |
} | |
private Instance deregister(Instance instance) { | |
log.info("Deregistered {}", instance); | |
return instance.deregister(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.Duration; | |
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository; | |
import de.codecentric.boot.admin.server.domain.events.InstanceEvent; | |
import org.reactivestreams.Publisher; | |
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.Configuration; | |
// inspired by: https://github.com/codecentric/spring-boot-admin/issues/535#issuecomment-493010425 | |
@Configuration | |
public class DeregisterOfflineConfiguration { | |
@Bean(initMethod = "start", destroyMethod = "stop") | |
@ConditionalOnMissingBean | |
public DeregisterOfflineTrigger deregisterOfflineTrigger( | |
DeregisterOffline deregisterOffline, | |
Publisher<InstanceEvent> events | |
) { | |
DeregisterOfflineTrigger trigger = new DeregisterOfflineTrigger(deregisterOffline, events); | |
trigger.setInterval(Duration.ofMinutes(1)); | |
trigger.setLifetime(Duration.ofMinutes(1)); | |
return trigger; | |
} | |
@Bean | |
@ConditionalOnMissingBean | |
public DeregisterOffline deregisterOffline(InstanceRepository instanceRepository) { | |
return new DeregisterOffline(instanceRepository); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time.Duration; | |
import de.codecentric.boot.admin.server.domain.events.InstanceEvent; | |
import de.codecentric.boot.admin.server.domain.events.InstanceRegisteredEvent; | |
import de.codecentric.boot.admin.server.domain.events.InstanceRegistrationUpdatedEvent; | |
import de.codecentric.boot.admin.server.domain.values.InstanceId; | |
import de.codecentric.boot.admin.server.services.AbstractEventHandler; | |
import de.codecentric.boot.admin.server.services.IntervalCheck; | |
import org.reactivestreams.Publisher; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import reactor.core.publisher.Flux; | |
import reactor.core.publisher.Mono; | |
import reactor.core.scheduler.Scheduler; | |
import reactor.core.scheduler.Schedulers; | |
// inspired by: https://github.com/codecentric/spring-boot-admin/issues/535#issuecomment-493010425 | |
// almost identical to InfoUpdateTrigger | |
public class DeregisterOfflineTrigger extends AbstractEventHandler<InstanceEvent> { | |
private static final Logger log = LoggerFactory.getLogger(DeregisterOfflineTrigger.class); | |
private final DeregisterOffline deregisterOffline; | |
private final IntervalCheck intervalCheck; | |
public DeregisterOfflineTrigger( | |
final DeregisterOffline deregisterOffline, | |
final Publisher<InstanceEvent> publisher | |
) { | |
super(publisher, InstanceEvent.class); | |
this.deregisterOffline = deregisterOffline; | |
this.intervalCheck = new IntervalCheck("deregister", this::deregisterCheck, Duration.ofMinutes(1), Duration.ofMinutes(1)); | |
} | |
@Override | |
protected Publisher<Void> handle(Flux<InstanceEvent> publisher) { | |
Scheduler scheduler = Schedulers.newSingle("offline-deregister"); | |
return publisher.subscribeOn(scheduler) | |
.filter(event -> event instanceof InstanceRegisteredEvent || | |
event instanceof InstanceRegistrationUpdatedEvent) | |
.flatMap(event -> this.deregisterCheck(event.getInstance())) | |
.doFinally(s -> scheduler.dispose()); | |
} | |
private Mono<Void> deregisterCheck(InstanceId instanceId) { | |
return deregisterOffline.deregisterCheck(instanceId) | |
.onErrorResume(e -> { | |
log.warn("Unexpected error during deregister check for {}", instanceId, e); | |
return Mono.empty(); | |
}) | |
.doFinally(s -> this.intervalCheck.markAsChecked(instanceId)); | |
} | |
@Override | |
public void start() { | |
super.start(); | |
this.intervalCheck.start(); | |
} | |
@Override | |
public void stop() { | |
super.stop(); | |
this.intervalCheck.stop(); | |
} | |
public void setInterval(Duration updateInterval) { | |
this.intervalCheck.setInterval(updateInterval); | |
} | |
public void setLifetime(Duration infoLifetime) { | |
this.intervalCheck.setMinRetention(infoLifetime); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment