Commit 46fe373a by Johannes Edmeier

replace long timestamps with instant

parent 562e402f
...@@ -22,7 +22,7 @@ import de.codecentric.boot.admin.server.notify.LoggingNotifier; ...@@ -22,7 +22,7 @@ import de.codecentric.boot.admin.server.notify.LoggingNotifier;
import de.codecentric.boot.admin.server.notify.RemindingNotifier; import de.codecentric.boot.admin.server.notify.RemindingNotifier;
import de.codecentric.boot.admin.server.notify.filter.FilteringNotifier; import de.codecentric.boot.admin.server.notify.filter.FilteringNotifier;
import java.util.concurrent.TimeUnit; import java.time.Duration;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
...@@ -84,7 +84,7 @@ public class SpringBootAdminApplication { ...@@ -84,7 +84,7 @@ public class SpringBootAdminApplication {
@Primary @Primary
public RemindingNotifier remindingNotifier() { public RemindingNotifier remindingNotifier() {
RemindingNotifier notifier = new RemindingNotifier(filteringNotifier(), repository); RemindingNotifier notifier = new RemindingNotifier(filteringNotifier(), repository);
notifier.setReminderPeriod(TimeUnit.SECONDS.toMillis(10)); notifier.setReminderPeriod(Duration.ofMinutes(10));
return notifier; return notifier;
} }
......
...@@ -22,7 +22,7 @@ import de.codecentric.boot.admin.server.notify.LoggingNotifier; ...@@ -22,7 +22,7 @@ import de.codecentric.boot.admin.server.notify.LoggingNotifier;
import de.codecentric.boot.admin.server.notify.RemindingNotifier; import de.codecentric.boot.admin.server.notify.RemindingNotifier;
import de.codecentric.boot.admin.server.notify.filter.FilteringNotifier; import de.codecentric.boot.admin.server.notify.filter.FilteringNotifier;
import java.util.concurrent.TimeUnit; import java.time.Duration;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
...@@ -92,7 +92,7 @@ public class SpringBootAdminApplication { ...@@ -92,7 +92,7 @@ public class SpringBootAdminApplication {
@Primary @Primary
public RemindingNotifier remindingNotifier() { public RemindingNotifier remindingNotifier() {
RemindingNotifier notifier = new RemindingNotifier(filteringNotifier(), repository); RemindingNotifier notifier = new RemindingNotifier(filteringNotifier(), repository);
notifier.setReminderPeriod(TimeUnit.SECONDS.toMillis(10)); notifier.setReminderPeriod(Duration.ofMinutes(10));
return notifier; return notifier;
} }
......
/* /*
* 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.
...@@ -30,6 +30,7 @@ import de.codecentric.boot.admin.server.domain.values.Registration; ...@@ -30,6 +30,7 @@ import de.codecentric.boot.admin.server.domain.values.Registration;
import de.codecentric.boot.admin.server.domain.values.StatusInfo; import de.codecentric.boot.admin.server.domain.values.StatusInfo;
import java.io.Serializable; import java.io.Serializable;
import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
...@@ -53,21 +54,20 @@ public class Instance implements Serializable { ...@@ -53,21 +54,20 @@ public class Instance implements Serializable {
private final Registration registration; private final Registration registration;
private final boolean registered; private final boolean registered;
private final StatusInfo statusInfo; private final StatusInfo statusInfo;
private final long statusTimestamp; private final Instant statusTimestamp;
private final Info info; private final Info info;
private final List<InstanceEvent> unsavedEvents; private final List<InstanceEvent> unsavedEvents;
private final Endpoints endpoints; private final Endpoints endpoints;
private Instance(InstanceId id) { private Instance(InstanceId id) {
this(id, -1L, null, false, StatusInfo.ofUnknown(), -1L, Info.empty(), Endpoints.empty(), emptyList()); this(id, -1L, null, false, StatusInfo.ofUnknown(), Instant.EPOCH, Info.empty(), Endpoints.empty(), emptyList());
} }
private Instance(InstanceId id, private Instance(InstanceId id,
long version, long version,
Registration registration, Registration registration,
boolean registered, boolean registered,
StatusInfo statusInfo, StatusInfo statusInfo, Instant statusTimestamp,
long statusTimestamp,
Info info, Info info,
Endpoints endpoints, Endpoints endpoints,
List<InstanceEvent> unsavedEvents) { List<InstanceEvent> unsavedEvents) {
......
/* /*
* 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.domain.events; ...@@ -18,6 +18,7 @@ package de.codecentric.boot.admin.server.domain.events;
import de.codecentric.boot.admin.server.domain.values.InstanceId; import de.codecentric.boot.admin.server.domain.values.InstanceId;
import java.io.Serializable; import java.io.Serializable;
import java.time.Instant;
/** /**
* Abstract Event regarding registered instances * Abstract Event regarding registered instances
...@@ -29,13 +30,13 @@ public abstract class InstanceEvent implements Serializable { ...@@ -29,13 +30,13 @@ public abstract class InstanceEvent implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final InstanceId instance; private final InstanceId instance;
private final long version; private final long version;
private final long timestamp; private final Instant timestamp;
private final String type; private final String type;
protected InstanceEvent(InstanceId instance, long version, String type) { protected InstanceEvent(InstanceId instance, long version, String type) {
this.instance = instance; this.instance = instance;
this.version = version; this.version = version;
this.timestamp = System.currentTimeMillis(); this.timestamp = Instant.now();
this.type = type; this.type = type;
} }
} }
/* /*
* 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.
...@@ -33,13 +33,13 @@ import java.util.function.Function; ...@@ -33,13 +33,13 @@ import java.util.function.Function;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import static java.util.Comparator.comparingLong; import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.reducing; import static java.util.stream.Collectors.reducing;
public abstract class ConcurrentMapEventStore extends InstanceEventPublisher implements InstanceEventStore { public abstract class ConcurrentMapEventStore extends InstanceEventPublisher implements InstanceEventStore {
private static final Logger log = LoggerFactory.getLogger(ConcurrentMapEventStore.class); private static final Logger log = LoggerFactory.getLogger(ConcurrentMapEventStore.class);
private static final Comparator<InstanceEvent> byTimestampAndIdAndVersion = comparingLong( private static final Comparator<InstanceEvent> byTimestampAndIdAndVersion = comparing(
InstanceEvent::getTimestamp).thenComparing(InstanceEvent::getInstance) InstanceEvent::getTimestamp).thenComparing(InstanceEvent::getInstance)
.thenComparing(InstanceEvent::getVersion); .thenComparing(InstanceEvent::getVersion);
private final int maxLogSizePerAggregate; private final int maxLogSizePerAggregate;
......
/* /*
* 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.
...@@ -23,10 +23,11 @@ import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent ...@@ -23,10 +23,11 @@ import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent
import de.codecentric.boot.admin.server.domain.values.InstanceId; import de.codecentric.boot.admin.server.domain.values.InstanceId;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
...@@ -36,7 +37,7 @@ import org.springframework.util.Assert; ...@@ -36,7 +37,7 @@ import org.springframework.util.Assert;
*/ */
public class RemindingNotifier extends AbstractEventNotifier { public class RemindingNotifier extends AbstractEventNotifier {
private final ConcurrentHashMap<InstanceId, Reminder> reminders = new ConcurrentHashMap<>(); private final ConcurrentHashMap<InstanceId, Reminder> reminders = new ConcurrentHashMap<>();
private long reminderPeriod = TimeUnit.MINUTES.toMillis(10L); private Duration reminderPeriod = Duration.ofMinutes(10);
private String[] reminderStatuses = {"DOWN", "OFFLINE"}; private String[] reminderStatuses = {"DOWN", "OFFLINE"};
private final Notifier delegate; private final Notifier delegate;
...@@ -58,9 +59,9 @@ public class RemindingNotifier extends AbstractEventNotifier { ...@@ -58,9 +59,9 @@ public class RemindingNotifier extends AbstractEventNotifier {
} }
public void sendReminders() { public void sendReminders() {
long now = System.currentTimeMillis(); Instant now = Instant.now();
for (Reminder reminder : new ArrayList<>(reminders.values())) { for (Reminder reminder : new ArrayList<>(reminders.values())) {
if (now - reminder.getLastNotification() > reminderPeriod) { if (reminder.getLastNotification().plus(reminderPeriod).isBefore(now)) {
reminder.setLastNotification(now); reminder.setLastNotification(now);
delegate.notify(reminder.getEvent()); delegate.notify(reminder.getEvent());
} }
...@@ -86,7 +87,7 @@ public class RemindingNotifier extends AbstractEventNotifier { ...@@ -86,7 +87,7 @@ public class RemindingNotifier extends AbstractEventNotifier {
return false; return false;
} }
public void setReminderPeriod(long reminderPeriod) { public void setReminderPeriod(Duration reminderPeriod) {
this.reminderPeriod = reminderPeriod; this.reminderPeriod = reminderPeriod;
} }
...@@ -98,18 +99,18 @@ public class RemindingNotifier extends AbstractEventNotifier { ...@@ -98,18 +99,18 @@ public class RemindingNotifier extends AbstractEventNotifier {
private static class Reminder { private static class Reminder {
private final InstanceEvent event; private final InstanceEvent event;
private long lastNotification; private Instant lastNotification;
private Reminder(InstanceEvent event) { private Reminder(InstanceEvent event) {
this.event = event; this.event = event;
this.lastNotification = event.getTimestamp(); this.lastNotification = event.getTimestamp();
} }
public void setLastNotification(long lastNotification) { public void setLastNotification(Instant lastNotification) {
this.lastNotification = lastNotification; this.lastNotification = lastNotification;
} }
public long getLastNotification() { public Instant getLastNotification() {
return lastNotification; return lastNotification;
} }
......
/* /*
* 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,10 +18,12 @@ package de.codecentric.boot.admin.server.notify.filter; ...@@ -18,10 +18,12 @@ package de.codecentric.boot.admin.server.notify.filter;
import de.codecentric.boot.admin.server.domain.entities.Instance; import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent; import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import java.time.Instant;
public class ApplicationNameNotificationFilter extends ExpiringNotificationFilter { public class ApplicationNameNotificationFilter extends ExpiringNotificationFilter {
private final String name; private final String name;
public ApplicationNameNotificationFilter(String name, long expiry) { public ApplicationNameNotificationFilter(String name, Instant expiry) {
super(expiry); super(expiry);
this.name = name; this.name = name;
} }
......
/* /*
* 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,15 +18,17 @@ package de.codecentric.boot.admin.server.notify.filter; ...@@ -18,15 +18,17 @@ package de.codecentric.boot.admin.server.notify.filter;
import de.codecentric.boot.admin.server.domain.entities.Instance; import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent; import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import java.time.Instant;
public abstract class ExpiringNotificationFilter implements NotificationFilter { public abstract class ExpiringNotificationFilter implements NotificationFilter {
private final long expiry; private final Instant expiry;
public ExpiringNotificationFilter(long expiry) { public ExpiringNotificationFilter(Instant expiry) {
this.expiry = expiry; this.expiry = expiry;
} }
public boolean isExpired() { public boolean isExpired() {
return expiry >= 0 && expiry < System.currentTimeMillis(); return expiry != null && expiry.isBefore(Instant.now());
} }
@Override @Override
...@@ -36,7 +38,7 @@ public abstract class ExpiringNotificationFilter implements NotificationFilter { ...@@ -36,7 +38,7 @@ public abstract class ExpiringNotificationFilter implements NotificationFilter {
protected abstract boolean doFilter(InstanceEvent event, Instance instance); protected abstract boolean doFilter(InstanceEvent event, Instance instance);
public long getExpiry() { public Instant getExpiry() {
return expiry; return expiry;
} }
} }
\ No newline at end of file
/* /*
* 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.
...@@ -23,6 +23,7 @@ import de.codecentric.boot.admin.server.notify.Notifier; ...@@ -23,6 +23,7 @@ import de.codecentric.boot.admin.server.notify.Notifier;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.time.Duration; import java.time.Duration;
import java.time.Instant;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -43,7 +44,7 @@ public class FilteringNotifier extends AbstractEventNotifier { ...@@ -43,7 +44,7 @@ public class FilteringNotifier extends AbstractEventNotifier {
private static final Logger LOGGER = LoggerFactory.getLogger(FilteringNotifier.class); private static final Logger LOGGER = LoggerFactory.getLogger(FilteringNotifier.class);
private final ConcurrentMap<String, NotificationFilter> filters = new ConcurrentHashMap<>(); private final ConcurrentMap<String, NotificationFilter> filters = new ConcurrentHashMap<>();
private final Notifier delegate; private final Notifier delegate;
private long lastCleanup; private Instant lastCleanup = Instant.EPOCH;
private Duration cleanupInterval = Duration.ofSeconds(10); private Duration cleanupInterval = Duration.ofSeconds(10);
private AtomicLong counter = new AtomicLong(); private AtomicLong counter = new AtomicLong();
...@@ -79,8 +80,8 @@ public class FilteringNotifier extends AbstractEventNotifier { ...@@ -79,8 +80,8 @@ public class FilteringNotifier extends AbstractEventNotifier {
} }
private void cleanUp() { private void cleanUp() {
long now = System.currentTimeMillis(); Instant now = Instant.now();
if (lastCleanup + cleanupInterval.toMillis() > now) { if (lastCleanup.plus(cleanupInterval).isAfter(now)) {
return; return;
} }
lastCleanup = now; lastCleanup = now;
......
/* /*
* 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.
...@@ -19,10 +19,12 @@ import de.codecentric.boot.admin.server.domain.entities.Instance; ...@@ -19,10 +19,12 @@ import de.codecentric.boot.admin.server.domain.entities.Instance;
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.values.InstanceId; import de.codecentric.boot.admin.server.domain.values.InstanceId;
import java.time.Instant;
public class InstanceIdNotificationFilter extends ExpiringNotificationFilter { public class InstanceIdNotificationFilter extends ExpiringNotificationFilter {
private final InstanceId id; private final InstanceId id;
public InstanceIdNotificationFilter(InstanceId id, long expiry) { public InstanceIdNotificationFilter(InstanceId id, Instant expiry) {
super(expiry); super(expiry);
this.id = id; this.id = id;
} }
......
/* /*
* 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.
...@@ -22,6 +22,8 @@ import de.codecentric.boot.admin.server.notify.filter.InstanceIdNotificationFilt ...@@ -22,6 +22,8 @@ import de.codecentric.boot.admin.server.notify.filter.InstanceIdNotificationFilt
import de.codecentric.boot.admin.server.notify.filter.NotificationFilter; import de.codecentric.boot.admin.server.notify.filter.NotificationFilter;
import de.codecentric.boot.admin.server.web.AdminController; import de.codecentric.boot.admin.server.web.AdminController;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
...@@ -57,7 +59,7 @@ public class NotificationFilterController { ...@@ -57,7 +59,7 @@ public class NotificationFilterController {
@PostMapping(path = "/notifications/filters", produces = MimeTypeUtils.APPLICATION_JSON_VALUE) @PostMapping(path = "/notifications/filters", produces = MimeTypeUtils.APPLICATION_JSON_VALUE)
public ResponseEntity<?> addFilter(@RequestParam(name = "id", required = false) String id, public ResponseEntity<?> addFilter(@RequestParam(name = "id", required = false) String id,
@RequestParam(name = "name", required = false) String name, @RequestParam(name = "name", required = false) String name,
@RequestParam(name = "ttl", required = false, defaultValue = "-1") long ttl) { @RequestParam(name = "ttl", required = false) Duration ttl) {
if (hasText(id) || hasText(name)) { if (hasText(id) || hasText(name)) {
NotificationFilter filter = createFilter(hasText(id) ? InstanceId.of(id) : null, name, ttl); NotificationFilter filter = createFilter(hasText(id) ? InstanceId.of(id) : null, name, ttl);
String filterId = filteringNotifier.addFilter(filter); String filterId = filteringNotifier.addFilter(filter);
...@@ -77,8 +79,8 @@ public class NotificationFilterController { ...@@ -77,8 +79,8 @@ public class NotificationFilterController {
} }
} }
private NotificationFilter createFilter(InstanceId id, String name, long ttl) { private NotificationFilter createFilter(InstanceId id, String name, Duration ttl) {
long expiry = ttl > 0L ? System.currentTimeMillis() + ttl : ttl; Instant expiry = ttl != null ? Instant.now().plus(ttl) : null;
return id != null ? return id != null ?
new InstanceIdNotificationFilter(id, expiry) : new InstanceIdNotificationFilter(id, expiry) :
......
/* /*
* 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.
...@@ -26,6 +26,7 @@ import reactor.core.scheduler.Schedulers; ...@@ -26,6 +26,7 @@ import reactor.core.scheduler.Schedulers;
import reactor.retry.Retry; import reactor.retry.Retry;
import java.time.Duration; import java.time.Duration;
import java.time.Instant;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
...@@ -36,7 +37,7 @@ import org.slf4j.LoggerFactory; ...@@ -36,7 +37,7 @@ import org.slf4j.LoggerFactory;
public class StatusUpdateTrigger extends ResubscribingEventHandler<InstanceRegisteredEvent> { public class StatusUpdateTrigger extends ResubscribingEventHandler<InstanceRegisteredEvent> {
private static final Logger log = LoggerFactory.getLogger(StatusUpdateTrigger.class); private static final Logger log = LoggerFactory.getLogger(StatusUpdateTrigger.class);
private final StatusUpdater statusUpdater; private final StatusUpdater statusUpdater;
private Map<InstanceId, Long> lastQueried = new HashMap<>(); private Map<InstanceId, Instant> lastQueried = new HashMap<>();
private Duration updateInterval = Duration.ofSeconds(10); private Duration updateInterval = Duration.ofSeconds(10);
private Duration statusLifetime = Duration.ofSeconds(10); private Duration statusLifetime = Duration.ofSeconds(10);
private Disposable intervalSubscription; private Disposable intervalSubscription;
...@@ -79,17 +80,15 @@ public class StatusUpdateTrigger extends ResubscribingEventHandler<InstanceRegis ...@@ -79,17 +80,15 @@ public class StatusUpdateTrigger extends ResubscribingEventHandler<InstanceRegis
protected Mono<Void> updateStatusForAllInstances() { protected Mono<Void> updateStatusForAllInstances() {
log.debug("Updating status for all instances"); log.debug("Updating status for all instances");
long expiryInstant = System.currentTimeMillis() - statusLifetime.toMillis(); Instant expiryInstant = Instant.now().minus(statusLifetime);
return Flux.fromIterable(lastQueried.entrySet()) return Flux.fromIterable(lastQueried.entrySet()).filter(e -> e.getValue().isBefore(expiryInstant))
.filter(e -> e.getValue() < expiryInstant)
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
.flatMap(this::updateStatus) .flatMap(this::updateStatus)
.then(); .then();
} }
protected Mono<Void> updateStatus(InstanceId instanceId) { protected Mono<Void> updateStatus(InstanceId instanceId) {
return statusUpdater.updateStatus(instanceId) return statusUpdater.updateStatus(instanceId).doFinally((s) -> lastQueried.put(instanceId, Instant.now()));
.doFinally((s) -> lastQueried.put(instanceId, System.currentTimeMillis()));
} }
public void setUpdateInterval(Duration updateInterval) { public void setUpdateInterval(Duration updateInterval) {
......
/* /*
* 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.
...@@ -26,6 +26,7 @@ import reactor.util.function.Tuple2; ...@@ -26,6 +26,7 @@ import reactor.util.function.Tuple2;
import reactor.util.function.Tuples; import reactor.util.function.Tuples;
import java.time.Duration; import java.time.Duration;
import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -100,7 +101,7 @@ public class ApplicationsController { ...@@ -100,7 +101,7 @@ public class ApplicationsController {
Application group = new Application(name); Application group = new Application(name);
group.setInstances(instanceList); group.setInstances(instanceList);
group.setVersion(getVersion(instanceList)); group.setVersion(getVersion(instanceList));
Tuple2<String, Long> status = getStatus(instanceList); Tuple2<String, Instant> status = getStatus(instanceList);
group.setStatus(status.getT1()); group.setStatus(status.getT1());
group.setStatusTimestamp(status.getT2()); group.setStatusTimestamp(status.getT2());
return group; return group;
...@@ -123,24 +124,24 @@ public class ApplicationsController { ...@@ -123,24 +124,24 @@ public class ApplicationsController {
} }
} }
protected Tuple2<String, Long> getStatus(List<Instance> instances) { protected Tuple2<String, Instant> getStatus(List<Instance> instances) {
//TODO: Correct is just a second readmodel for groups //TODO: Correct is just a second readmodel for groups
Map<String, Long> statusWithTime = instances.stream() Map<String, Instant> statusWithTime = instances.stream()
.collect(toMap(instance -> instance.getStatusInfo().getStatus(), .collect(toMap(instance -> instance.getStatusInfo().getStatus(),
Instance::getStatusTimestamp, Math::min)); Instance::getStatusTimestamp, this::getMax));
if (statusWithTime.size() == 1) { if (statusWithTime.size() == 1) {
Map.Entry<String, Long> e = statusWithTime.entrySet().iterator().next(); Map.Entry<String, Instant> e = statusWithTime.entrySet().iterator().next();
return Tuples.of(e.getKey(), e.getValue()); return Tuples.of(e.getKey(), e.getValue());
} }
if (statusWithTime.containsKey(StatusInfo.STATUS_UP)) { if (statusWithTime.containsKey(StatusInfo.STATUS_UP)) {
Long oldestNonUp = statusWithTime.entrySet() Instant oldestNonUp = statusWithTime.entrySet()
.stream() .stream()
.filter(e -> !StatusInfo.STATUS_UP.equals(e.getKey())) .filter(e -> !StatusInfo.STATUS_UP.equals(e.getKey()))
.map(Map.Entry::getValue) .map(Map.Entry::getValue)
.min(naturalOrder()) .min(naturalOrder())
.orElse(-1L); .orElse(Instant.EPOCH);
long latest = Math.max(oldestNonUp, statusWithTime.getOrDefault(StatusInfo.STATUS_UP, -1L)); Instant latest = getMax(oldestNonUp, statusWithTime.getOrDefault(StatusInfo.STATUS_UP, Instant.EPOCH));
return Tuples.of(StatusInfo.STATUS_RESTRICTED, latest); return Tuples.of(StatusInfo.STATUS_RESTRICTED, latest);
} }
...@@ -148,7 +149,11 @@ public class ApplicationsController { ...@@ -148,7 +149,11 @@ public class ApplicationsController {
.stream() .stream()
.min(Map.Entry.comparingByKey(StatusInfo.severity())) .min(Map.Entry.comparingByKey(StatusInfo.severity()))
.map(e -> Tuples.of(e.getKey(), e.getValue())) .map(e -> Tuples.of(e.getKey(), e.getValue()))
.orElse(Tuples.of(StatusInfo.STATUS_UNKNOWN, -1L)); .orElse(Tuples.of(StatusInfo.STATUS_UNKNOWN, Instant.EPOCH));
}
private Instant getMax(Instant t1, Instant t2) {
return t1.compareTo(t2) >= 0 ? t1 : t2;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
...@@ -161,7 +166,7 @@ public class ApplicationsController { ...@@ -161,7 +166,7 @@ public class ApplicationsController {
private final String name; private final String name;
private String version; private String version;
private String status; private String status;
private long statusTimestamp; private Instant statusTimestamp;
private List<Instance> instances; private List<Instance> instances;
} }
} }
/* /*
* 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.
...@@ -26,6 +26,7 @@ import de.codecentric.boot.admin.server.domain.values.StatusInfo; ...@@ -26,6 +26,7 @@ import de.codecentric.boot.admin.server.domain.values.StatusInfo;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import reactor.test.StepVerifier; import reactor.test.StepVerifier;
import java.time.Duration;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
...@@ -49,7 +50,7 @@ public class RemindingNotifierTest { ...@@ -49,7 +50,7 @@ public class RemindingNotifierTest {
private InstanceRepository repository; private InstanceRepository repository;
@Before @Before
public void setUp() throws Exception { public void setUp() {
repository = mock(InstanceRepository.class); repository = mock(InstanceRepository.class);
when(repository.find(instance1.getId())).thenReturn(Mono.just(instance1)); when(repository.find(instance1.getId())).thenReturn(Mono.just(instance1));
when(repository.find(instance2.getId())).thenReturn(Mono.just(instance2)); when(repository.find(instance2.getId())).thenReturn(Mono.just(instance2));
...@@ -61,10 +62,10 @@ public class RemindingNotifierTest { ...@@ -61,10 +62,10 @@ public class RemindingNotifierTest {
} }
@Test @Test
public void test_remind() throws Exception { public void test_remind() {
TestNotifier notifier = new TestNotifier(); TestNotifier notifier = new TestNotifier();
RemindingNotifier reminder = new RemindingNotifier(notifier, repository); RemindingNotifier reminder = new RemindingNotifier(notifier, repository);
reminder.setReminderPeriod(-1000L); reminder.setReminderPeriod(Duration.ZERO);
StepVerifier.create(reminder.notify(appDown)).verifyComplete(); StepVerifier.create(reminder.notify(appDown)).verifyComplete();
StepVerifier.create(reminder.notify(otherAppUp)).verifyComplete(); StepVerifier.create(reminder.notify(otherAppUp)).verifyComplete();
...@@ -76,10 +77,10 @@ public class RemindingNotifierTest { ...@@ -76,10 +77,10 @@ public class RemindingNotifierTest {
} }
@Test @Test
public void test_no_remind_after_up() throws Exception { public void test_no_remind_after_up() {
TestNotifier notifier = new TestNotifier(); TestNotifier notifier = new TestNotifier();
RemindingNotifier reminder = new RemindingNotifier(notifier, repository); RemindingNotifier reminder = new RemindingNotifier(notifier, repository);
reminder.setReminderPeriod(0L); reminder.setReminderPeriod(Duration.ZERO);
StepVerifier.create(reminder.notify(appDown)).verifyComplete(); StepVerifier.create(reminder.notify(appDown)).verifyComplete();
StepVerifier.create(reminder.notify(appUp)).verifyComplete(); StepVerifier.create(reminder.notify(appUp)).verifyComplete();
...@@ -89,10 +90,10 @@ public class RemindingNotifierTest { ...@@ -89,10 +90,10 @@ public class RemindingNotifierTest {
} }
@Test @Test
public void test_no_remind_before_end() throws Exception { public void test_no_remind_before_end() {
TestNotifier notifier = new TestNotifier(); TestNotifier notifier = new TestNotifier();
RemindingNotifier reminder = new RemindingNotifier(notifier, repository); RemindingNotifier reminder = new RemindingNotifier(notifier, repository);
reminder.setReminderPeriod(Long.MAX_VALUE); reminder.setReminderPeriod(Duration.ofHours(24));
StepVerifier.create(reminder.notify(appDown)).verifyComplete(); StepVerifier.create(reminder.notify(appDown)).verifyComplete();
reminder.sendReminders(); reminder.sendReminders();
......
/* /*
* 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.
...@@ -26,6 +26,7 @@ import reactor.core.publisher.Mono; ...@@ -26,6 +26,7 @@ import reactor.core.publisher.Mono;
import reactor.test.StepVerifier; import reactor.test.StepVerifier;
import java.time.Duration; import java.time.Duration;
import java.time.Instant;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
...@@ -56,8 +57,9 @@ public class FilteringNotifierTest { ...@@ -56,8 +57,9 @@ public class FilteringNotifierTest {
FilteringNotifier notifier = new FilteringNotifier(new TestNotifier(), repository); FilteringNotifier notifier = new FilteringNotifier(new TestNotifier(), repository);
notifier.setCleanupInterval(Duration.ZERO); notifier.setCleanupInterval(Duration.ZERO);
String id1 = notifier.addFilter(new ApplicationNameNotificationFilter("foo", 0L)); String id1 = notifier.addFilter(
String id2 = notifier.addFilter(new ApplicationNameNotificationFilter("bar", -1L)); new ApplicationNameNotificationFilter("foo", Instant.now().minus(Duration.ofSeconds(1))));
String id2 = notifier.addFilter(new ApplicationNameNotificationFilter("bar", null));
assertThat(notifier.getNotificationFilters()).containsKey(id1).containsKey(id2); assertThat(notifier.getNotificationFilters()).containsKey(id1).containsKey(id2);
......
/* /*
* 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.
...@@ -28,7 +28,7 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -28,7 +28,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class InstanceIdNotificationFilterTest { public class InstanceIdNotificationFilterTest {
@Test @Test
public void test_filterByName() { public void test_filterByName() {
NotificationFilter filter = new InstanceIdNotificationFilter(InstanceId.of("cafebabe"), -1L); NotificationFilter filter = new InstanceIdNotificationFilter(InstanceId.of("cafebabe"), null);
Instance filteredInstance = Instance.create(InstanceId.of("cafebabe")) Instance filteredInstance = Instance.create(InstanceId.of("cafebabe"))
.register(Registration.create("foo", "http://health").build()); .register(Registration.create("foo", "http://health").build());
......
/* /*
* 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.
...@@ -21,6 +21,8 @@ import de.codecentric.boot.admin.server.domain.events.InstanceRegisteredEvent; ...@@ -21,6 +21,8 @@ import de.codecentric.boot.admin.server.domain.events.InstanceRegisteredEvent;
import de.codecentric.boot.admin.server.domain.values.InstanceId; import de.codecentric.boot.admin.server.domain.values.InstanceId;
import de.codecentric.boot.admin.server.domain.values.Registration; import de.codecentric.boot.admin.server.domain.values.Registration;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.junit.Test; import org.junit.Test;
...@@ -30,7 +32,7 @@ public class InstanceNameNotificationFilterTest { ...@@ -30,7 +32,7 @@ public class InstanceNameNotificationFilterTest {
@Test @Test
public void test_filterByName() { public void test_filterByName() {
NotificationFilter filter = new ApplicationNameNotificationFilter("foo", -1L); NotificationFilter filter = new ApplicationNameNotificationFilter("foo", null);
Instance filteredInstance = Instance.create(InstanceId.of("-")) Instance filteredInstance = Instance.create(InstanceId.of("-"))
.register(Registration.create("foo", "http://health").build()); .register(Registration.create("foo", "http://health").build());
...@@ -47,16 +49,17 @@ public class InstanceNameNotificationFilterTest { ...@@ -47,16 +49,17 @@ public class InstanceNameNotificationFilterTest {
@Test @Test
public void test_expiry() throws InterruptedException { public void test_expiry() throws InterruptedException {
ExpiringNotificationFilter filterForever = new ApplicationNameNotificationFilter("foo", -1L); ExpiringNotificationFilter filterForever = new ApplicationNameNotificationFilter("foo", null);
ExpiringNotificationFilter filterExpired = new ApplicationNameNotificationFilter("foo", 0L); ExpiringNotificationFilter filterExpired = new ApplicationNameNotificationFilter("foo",
Instant.now().minus(Duration.ofSeconds(1)));
ExpiringNotificationFilter filterLong = new ApplicationNameNotificationFilter("foo", ExpiringNotificationFilter filterLong = new ApplicationNameNotificationFilter("foo",
System.currentTimeMillis() + 500L); Instant.now().plus(Duration.ofMillis(100)));
assertThat(filterForever.isExpired()).isFalse(); assertThat(filterForever.isExpired()).isFalse();
assertThat(filterLong.isExpired()).isFalse(); assertThat(filterLong.isExpired()).isFalse();
assertThat(filterExpired.isExpired()).isTrue(); assertThat(filterExpired.isExpired()).isTrue();
TimeUnit.MILLISECONDS.sleep(501); TimeUnit.MILLISECONDS.sleep(200);
assertThat(filterLong.isExpired()).isTrue(); assertThat(filterLong.isExpired()).isTrue();
} }
} }
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