Commit fa35de89 by Johannes Edmeier

Refresh info when registration has changed.

The info should be updated when the registration has changed. In order to prevent a stale instance info, the sba client includes a "startup" timestamp in the metadata as default. So when the instance is restarted the registration changes and the info is updated, even when the instance isn't considered as down in between. To prevent this when using a discovery client you need to add a value to the metadata which changes with every restart. (e.g. `random=${random.value}`) fixes #556
parent 6aefa229
/* /*
* Copyright 2014-2017 the original author or authors. * Copyright 2014-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -18,6 +18,7 @@ package de.codecentric.boot.admin.server.services; ...@@ -18,6 +18,7 @@ package de.codecentric.boot.admin.server.services;
import de.codecentric.boot.admin.server.domain.events.InstanceEndpointsDetectedEvent; import de.codecentric.boot.admin.server.domain.events.InstanceEndpointsDetectedEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent; import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceRegistrationUpdatedEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent; import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
...@@ -37,7 +38,8 @@ public class InfoUpdateTrigger extends ResubscribingEventHandler<InstanceEvent> ...@@ -37,7 +38,8 @@ public class InfoUpdateTrigger extends ResubscribingEventHandler<InstanceEvent>
protected Publisher<?> handle(Flux<InstanceEvent> publisher) { protected Publisher<?> handle(Flux<InstanceEvent> publisher) {
return publisher.subscribeOn(Schedulers.newSingle("info-updater")) return publisher.subscribeOn(Schedulers.newSingle("info-updater"))
.filter(event -> event instanceof InstanceEndpointsDetectedEvent || .filter(event -> event instanceof InstanceEndpointsDetectedEvent ||
event instanceof InstanceStatusChangedEvent) event instanceof InstanceStatusChangedEvent ||
event instanceof InstanceRegistrationUpdatedEvent)
.flatMap(this::updateInfo); .flatMap(this::updateInfo);
} }
......
/* /*
* Copyright 2014-2017 the original author or authors. * Copyright 2014-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -20,6 +20,7 @@ import de.codecentric.boot.admin.server.domain.entities.Instance; ...@@ -20,6 +20,7 @@ import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.events.InstanceEndpointsDetectedEvent; import de.codecentric.boot.admin.server.domain.events.InstanceEndpointsDetectedEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent; 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.InstanceRegisteredEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceRegistrationUpdatedEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent; import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
import de.codecentric.boot.admin.server.domain.values.Endpoints; import de.codecentric.boot.admin.server.domain.values.Endpoints;
import de.codecentric.boot.admin.server.domain.values.InstanceId; import de.codecentric.boot.admin.server.domain.values.InstanceId;
...@@ -69,6 +70,13 @@ public class InfoUpdateTriggerTest { ...@@ -69,6 +70,13 @@ public class InfoUpdateTriggerTest {
//then should update //then should update
verify(updater, times(1)).updateInfo(instance.getId()); verify(updater, times(1)).updateInfo(instance.getId());
//when registration updated event is emitted
clearInvocations(updater);
events.next(new InstanceRegistrationUpdatedEvent(instance.getId(), instance.getVersion(),
instance.getRegistration()));
//then should update
verify(updater, times(1)).updateInfo(instance.getId());
//when registered event is emitted but the trigger has been stopped //when registered event is emitted but the trigger has been stopped
trigger.stop(); trigger.stop();
clearInvocations(updater); clearInvocations(updater);
......
/* /*
* Copyright 2014-2017 the original author or authors. * Copyright 2014-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -20,6 +20,9 @@ import de.codecentric.boot.admin.client.config.InstanceProperties; ...@@ -20,6 +20,9 @@ import de.codecentric.boot.admin.client.config.InstanceProperties;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.EndpointPathProvider; import org.springframework.boot.actuate.autoconfigure.endpoint.web.EndpointPathProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
...@@ -39,13 +42,15 @@ import org.springframework.web.util.UriComponentsBuilder; ...@@ -39,13 +42,15 @@ import org.springframework.web.util.UriComponentsBuilder;
* @author Rene Felgenträger * @author Rene Felgenträger
*/ */
public class DefaultApplicationFactory implements ApplicationFactory { public class DefaultApplicationFactory implements ApplicationFactory {
private InstanceProperties instance; private final InstanceProperties instance;
private ServerProperties server; private final ServerProperties server;
private ManagementServerProperties management; private final ManagementServerProperties management;
private final EndpointPathProvider endpointPathProvider;
private final WebEndpointProperties webEndpoint;
private final OffsetDateTime timestamp;
private Integer localServerPort; private Integer localServerPort;
private Integer localManagementPort; private Integer localManagementPort;
private EndpointPathProvider endpointPathProvider;
private WebEndpointProperties webEndpoint;
public DefaultApplicationFactory(InstanceProperties instance, public DefaultApplicationFactory(InstanceProperties instance,
ManagementServerProperties management, ManagementServerProperties management,
...@@ -57,6 +62,7 @@ public class DefaultApplicationFactory implements ApplicationFactory { ...@@ -57,6 +62,7 @@ public class DefaultApplicationFactory implements ApplicationFactory {
this.server = server; this.server = server;
this.endpointPathProvider = endpointPathProvider; this.endpointPathProvider = endpointPathProvider;
this.webEndpoint = webEndpoint; this.webEndpoint = webEndpoint;
this.timestamp = OffsetDateTime.now();
} }
@Override @Override
...@@ -156,7 +162,13 @@ public class DefaultApplicationFactory implements ApplicationFactory { ...@@ -156,7 +162,13 @@ public class DefaultApplicationFactory implements ApplicationFactory {
} }
protected Map<String, String> getMetadata() { protected Map<String, String> getMetadata() {
if (instance.getMetadata().containsKey("startup")) {
return instance.getMetadata(); return instance.getMetadata();
} else {
Map<String, String> metadata = new LinkedHashMap<>();
metadata.put("startup", this.timestamp.format(DateTimeFormatter.ISO_DATE_TIME));
return metadata;
}
} }
protected String getServiceHost() { protected String getServiceHost() {
......
...@@ -26,7 +26,8 @@ import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; ...@@ -26,7 +26,8 @@ import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder;
import static com.github.tomakehurst.wiremock.client.WireMock.created; import static com.github.tomakehurst.wiremock.client.WireMock.created;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; import static com.github.tomakehurst.wiremock.client.WireMock.matching;
import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath;
import static com.github.tomakehurst.wiremock.client.WireMock.moreThanOrExactly; import static com.github.tomakehurst.wiremock.client.WireMock.moreThanOrExactly;
import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
...@@ -53,13 +54,13 @@ public abstract class AbstractClientApplicationTest { ...@@ -53,13 +54,13 @@ public abstract class AbstractClientApplicationTest {
Thread.sleep(1000L); Thread.sleep(1000L);
String serviceHost = "http://localhost:" + getServerPort(); String serviceHost = "http://localhost:" + getServerPort();
String managementHost = "http://localhost:" + getManagementPort(); String managementHost = "http://localhost:" + getManagementPort();
String body = "{ \"name\" : \"Test-Client\"," + // RequestPatternBuilder request = postRequestedFor(urlEqualTo("/instances"));
" \"managementUrl\" : \"" + managementHost + "/mgmt\"," + // request.withHeader("Content-Type", equalTo("application/json"))
" \"healthUrl\" : \"" + managementHost + "/mgmt/health\"," + // .withRequestBody(matchingJsonPath("$.name", equalTo("Test-Client")))
" \"serviceUrl\" : \"" + serviceHost + "/\", " + // .withRequestBody(matchingJsonPath("$.healthUrl", equalTo(managementHost + "/mgmt/health")))
" \"metadata\" : {} }"; .withRequestBody(matchingJsonPath("$.managementUrl", equalTo(managementHost + "/mgmt")))
RequestPatternBuilder request = postRequestedFor(urlEqualTo("/instances")).withHeader("Content-Type", .withRequestBody(matchingJsonPath("$.serviceUrl", equalTo(serviceHost + "/")))
equalTo("application/json")).withRequestBody(equalToJson(body)); .withRequestBody(matchingJsonPath("$.metadata.startup", matching(".+")));
verify(moreThanOrExactly(1), request); verify(moreThanOrExactly(1), request);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment