diff options
Diffstat (limited to 'service-monitor/src/main/java/com/yahoo/vespa/service/health/ApplicationHealthMonitor.java')
-rw-r--r-- | service-monitor/src/main/java/com/yahoo/vespa/service/health/ApplicationHealthMonitor.java | 40 |
1 files changed, 29 insertions, 11 deletions
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/health/ApplicationHealthMonitor.java b/service-monitor/src/main/java/com/yahoo/vespa/service/health/ApplicationHealthMonitor.java index e728d1ea914..873baeae710 100644 --- a/service-monitor/src/main/java/com/yahoo/vespa/service/health/ApplicationHealthMonitor.java +++ b/service-monitor/src/main/java/com/yahoo/vespa/service/health/ApplicationHealthMonitor.java @@ -8,13 +8,14 @@ import com.yahoo.vespa.applicationmodel.ConfigId; import com.yahoo.vespa.applicationmodel.ServiceStatus; import com.yahoo.vespa.applicationmodel.ServiceStatusInfo; import com.yahoo.vespa.applicationmodel.ServiceType; -import com.yahoo.vespa.service.model.ServiceId; +import com.yahoo.vespa.service.monitor.ServiceId; import com.yahoo.vespa.service.monitor.ServiceStatusProvider; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /** * Responsible for monitoring a whole application using /state/v1/health. @@ -24,6 +25,10 @@ import java.util.Set; class ApplicationHealthMonitor implements ServiceStatusProvider, AutoCloseable { private final ApplicationId applicationId; private final StateV1HealthModel healthModel; + + // Guards against concurrent access to monitors field w/objects in 1. monitor() (called from e.g. DuperModel), + // 2. getStatus() called from caching layer and Orchestrator above, and 3. REST calls to getAllServiceStatuses(). + private final Object guard = new Object(); private final Map<ServiceId, HealthMonitor> monitors = new HashMap<>(); ApplicationHealthMonitor(ApplicationId applicationId, StateV1HealthModel healthModel) { @@ -38,13 +43,15 @@ class ApplicationHealthMonitor implements ServiceStatusProvider, AutoCloseable { Map<ServiceId, HealthEndpoint> endpoints = healthModel.extractHealthEndpoints(applicationInfo); - // Remove obsolete monitors - Set<ServiceId> removed = new HashSet<>(monitors.keySet()); - removed.removeAll(endpoints.keySet()); - removed.stream().map(monitors::remove).forEach(HealthMonitor::close); + synchronized (guard) { + // Remove obsolete monitors + Set<ServiceId> removed = new HashSet<>(monitors.keySet()); + removed.removeAll(endpoints.keySet()); + removed.stream().map(monitors::remove).forEach(HealthMonitor::close); - // Add new monitors. - endpoints.forEach((serviceId, endpoint) -> monitors.computeIfAbsent(serviceId, ignoredId -> endpoint.startMonitoring())); + // Add new monitors. + endpoints.forEach((serviceId, endpoint) -> monitors.computeIfAbsent(serviceId, ignoredId -> endpoint.startMonitoring())); + } } @Override @@ -53,12 +60,23 @@ class ApplicationHealthMonitor implements ServiceStatusProvider, AutoCloseable { ServiceType serviceType, ConfigId configId) { ServiceId serviceId = new ServiceId(applicationId, clusterId, serviceType, configId); - HealthMonitor monitor = monitors.get(serviceId); - if (monitor == null) { - return new ServiceStatusInfo(ServiceStatus.NOT_CHECKED); + + synchronized (guard) { + HealthMonitor monitor = monitors.get(serviceId); + if (monitor == null) { + return new ServiceStatusInfo(ServiceStatus.NOT_CHECKED); + } + + return monitor.getStatus(); } + } - return monitor.getStatus(); + public Map<ServiceId, ServiceStatusInfo> getAllServiceStatuses() { + synchronized (guard) { + return monitors.entrySet().stream().collect(Collectors.toMap( + entry -> entry.getKey(), + entry -> entry.getValue().getStatus())); + } } @Override |