Commit b034099c by 赵天增

啦啦啦

parent c2ccd6dd
......@@ -15,3 +15,32 @@ management:
endpoint:
health:
show-details: ALWAYS
# 微服务列表,如果服务不存在会触发邮件提醒
spring:
boot:
admin:
notify:
mail:
enabled: true
to: tianzeng.zhao@medtap.cn
from: tianzeng.zhao@medtap.cn
services:
YJY-APPLICATION-USER,
YJY-APPLICATION-COMMON,
YJY-APPLICATION-WECHAT,
YJY-APPLICATION-PAYMENT,
YJY-APPLICATION-SERVICE,
YJY-APPLICATION-THIRD,
YJY-APPLICATION-DOCTOR,
YJY-APPLICATION-OPERATION,
YJY-APPLICATION-TRADE,
YJY-APPLICATION-SHOP,
YJY-APPLICATION-CRM,
OPERATION-API,
USER-API,
PROMOTION-API,
RESOURCE-API,
ITEM-API,
BABABABBABA
......@@ -21,6 +21,7 @@ import de.codecentric.boot.admin.server.domain.entities.SnapshottingInstanceRepo
import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import de.codecentric.boot.admin.server.eventstore.InMemoryEventStore;
import de.codecentric.boot.admin.server.eventstore.InstanceEventStore;
import de.codecentric.boot.admin.server.notify.ServicesList;
import de.codecentric.boot.admin.server.services.EndpointDetectionTrigger;
import de.codecentric.boot.admin.server.services.EndpointDetector;
import de.codecentric.boot.admin.server.services.HashingInstanceUrlIdGenerator;
......@@ -74,6 +75,10 @@ public class AdminServerAutoConfiguration {
}
@Bean
public ServicesList servicesList(){
return new ServicesList();
}
@Bean
@ConditionalOnMissingBean
public InstanceIdGenerator instanceIdGenerator() {
return new HashingInstanceUrlIdGenerator();
......
package de.codecentric.boot.admin.server.notify;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import javax.validation.constraints.Max;
import java.util.List;
@Component
public class ServicesList {
@Autowired
private Environment env;
public List<String> getServices() {
return env.getProperty("spring.boot.admin.services",List.class);
}
}
......@@ -20,20 +20,11 @@ import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.values.BuildVersion;
import de.codecentric.boot.admin.server.domain.values.StatusInfo;
import de.codecentric.boot.admin.server.eventstore.InstanceEventPublisher;
import de.codecentric.boot.admin.server.notify.ServicesList;
import de.codecentric.boot.admin.server.services.InstanceRegistry;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.ServerSentEvent;
......@@ -41,6 +32,14 @@ import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import static java.util.Comparator.naturalOrder;
import static java.util.stream.Collectors.toList;
......@@ -55,7 +54,7 @@ public class ApplicationsController {
private static final Logger log = LoggerFactory.getLogger(ApplicationsController.class);
private static final ServerSentEvent<?> PING = ServerSentEvent.builder().comment("ping").build();
private static final Flux<ServerSentEvent<?>> PING_FLUX = Flux.interval(Duration.ZERO, Duration.ofSeconds(10L))
.map(tick -> PING);
.map(tick -> PING);
private final InstanceRegistry registry;
private final InstanceEventPublisher eventPublisher;
......@@ -64,6 +63,10 @@ public class ApplicationsController {
this.eventPublisher = eventPublisher;
}
@Autowired
private ServicesList servicesList;
@GetMapping(path = "/applications", produces = MediaType.APPLICATION_JSON_VALUE)
public Flux<Application> applications() {
Flux<Application> applicationFlux = registry.getInstances()
......@@ -71,29 +74,64 @@ public class ApplicationsController {
.groupBy(instance -> instance.getRegistration().getName())
.flatMap(grouped -> toApplication(grouped.key(), grouped));
List<String> appNames = new ArrayList<>();
applicationFlux.subscribe(application -> appNames.add(application.getName()));
for (String appName : minus(servicesList.getServices(),appNames)) {
Application group = new Application(appName.toUpperCase());
group.setStatus("OFFINE");
group.setInstances(Collections.EMPTY_LIST);
applicationFlux = applicationFlux.concatWithValues(group);
}
return applicationFlux;
}
/**
* 求两数组的差集
*
* @param arr1 模板数组
* @param arr2 比较数组
* @return
*/
public static String[] minus(List<String> arr1, List<String> arr2) {
LinkedList<String> list = new LinkedList<>();
LinkedList<String> history = new LinkedList<>();
for (String str : arr1) {
if (!list.contains(str.toUpperCase())) {
list.add(str.toUpperCase());
}
}
for (String str : arr2) {
list.remove(str.toUpperCase());
}
String[] result = {};
return list.toArray(result);
}
@GetMapping(path = "/applications", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<Application>> applicationsStream() {
return Flux.from(eventPublisher)
.flatMap(event -> registry.getInstance(event.getInstance()))
.map(this::getApplicationForInstance)
.flatMap(group -> toApplication(group.getT1(), group.getT2()))
.map(application -> ServerSentEvent.builder(application).build())
.mergeWith(ping());
.flatMap(event -> registry.getInstance(event.getInstance()))
.map(this::getApplicationForInstance)
.flatMap(group -> toApplication(group.getT1(), group.getT2()))
.map(application -> ServerSentEvent.builder(application).build())
.mergeWith(ping());
}
@DeleteMapping(path = "/applications/{name}")
public Mono<ResponseEntity<Void>> unregister(@PathVariable("name") String name) {
log.debug("Unregister application with name '{}'", name);
return registry.getInstances(name)
.flatMap(instance -> registry.deregister(instance.getId()))
.collectList()
.map(
deregistered -> !deregistered.isEmpty() ? ResponseEntity.noContent().build() : ResponseEntity
.notFound()
.build());
.flatMap(instance -> registry.deregister(instance.getId()))
.collectList()
.map(
deregistered -> !deregistered.isEmpty() ? ResponseEntity.noContent().build() : ResponseEntity
.notFound()
.build());
}
protected Tuple2<String, Flux<Instance>> getApplicationForInstance(Instance instance) {
......@@ -107,8 +145,7 @@ public class ApplicationsController {
group.setInstances(instanceList);
group.setBuildVersion(getBuildVersion(instanceList));
Tuple2<String, Instant> status = getStatus(instanceList);
// group.setStatus(status.getT1());
group.setStatus("UP");
group.setStatus(status.getT1());
group.setStatusTimestamp(status.getT2());
return group;
});
......@@ -116,11 +153,11 @@ public class ApplicationsController {
protected BuildVersion getBuildVersion(List<Instance> instances) {
List<BuildVersion> versions = instances.stream()
.map(Instance::getBuildVersion)
.filter(Objects::nonNull)
.distinct()
.sorted()
.collect(toList());
.map(Instance::getBuildVersion)
.filter(Objects::nonNull)
.distinct()
.sorted()
.collect(toList());
if (versions.isEmpty()) {
return null;
} else if (versions.size() == 1) {
......@@ -133,8 +170,8 @@ public class ApplicationsController {
protected Tuple2<String, Instant> getStatus(List<Instance> instances) {
//TODO: Correct is just a second readmodel for groups
Map<String, Instant> statusWithTime = instances.stream()
.collect(toMap(instance -> instance.getStatusInfo().getStatus(),
Instance::getStatusTimestamp, this::getMax));
.collect(toMap(instance -> instance.getStatusInfo().getStatus(),
Instance::getStatusTimestamp, this::getMax));
if (statusWithTime.size() == 1) {
Map.Entry<String, Instant> e = statusWithTime.entrySet().iterator().next();
return Tuples.of(e.getKey(), e.getValue());
......@@ -142,20 +179,20 @@ public class ApplicationsController {
if (statusWithTime.containsKey(StatusInfo.STATUS_UP)) {
Instant oldestNonUp = statusWithTime.entrySet()
.stream()
.filter(e -> !StatusInfo.STATUS_UP.equals(e.getKey()))
.map(Map.Entry::getValue)
.min(naturalOrder())
.orElse(Instant.EPOCH);
.stream()
.filter(e -> !StatusInfo.STATUS_UP.equals(e.getKey()))
.map(Map.Entry::getValue)
.min(naturalOrder())
.orElse(Instant.EPOCH);
Instant latest = getMax(oldestNonUp, statusWithTime.getOrDefault(StatusInfo.STATUS_UP, Instant.EPOCH));
return Tuples.of(StatusInfo.STATUS_RESTRICTED, latest);
}
return statusWithTime.entrySet()
.stream()
.min(Map.Entry.comparingByKey(StatusInfo.severity()))
.map(e -> Tuples.of(e.getKey(), e.getValue()))
.orElse(Tuples.of(StatusInfo.STATUS_UNKNOWN, Instant.EPOCH));
.stream()
.min(Map.Entry.comparingByKey(StatusInfo.severity()))
.map(e -> Tuples.of(e.getKey(), e.getValue()))
.orElse(Tuples.of(StatusInfo.STATUS_UNKNOWN, Instant.EPOCH));
}
private Instant getMax(Instant t1, Instant t2) {
......
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