From b7ebdef22c2a221245abede2ed09267329a17f77 Mon Sep 17 00:00:00 2001 From: Adam Jordens Date: Fri, 18 Mar 2016 08:47:01 -0700 Subject: [PATCH] Include each ItemDAO in the health check - S3 just ensures it's refreshed itself in the past 45s - Cassandra* executes a query * Only CassandraApplicationDAO executes a query, the other DAOs just return true (just tests Cassandra connectivity which should be the same regardless of DAO) --- .../model/application/ApplicationDAO.groovy | 2 +- .../pipeline/StrategyRepository.groovy | 2 +- .../spinnaker/front50/model/S3Support.java | 9 ++++++- .../front50/config/Front50WebConfig.groovy | 25 +++++++++++++++++++ .../config/ItemDAOHealthIndicator.groovy | 18 ++++++------- .../config/ItemDAOHealthIndicatorSpec.groovy | 6 ++--- 6 files changed, 45 insertions(+), 17 deletions(-) rename front50-core/src/main/groovy/com/netflix/spinnaker/front50/config/ApplicationDAOProviderHealthIndicator.groovy => front50-web/src/main/groovy/com/netflix/spinnaker/front50/config/ItemDAOHealthIndicator.groovy (68%) rename front50-core/src/test/groovy/com/netflix/spinnaker/front50/config/ApplicationDAOProviderHealthIndicatorSpec.groovy => front50-web/src/test/groovy/com/netflix/spinnaker/front50/config/ItemDAOHealthIndicatorSpec.groovy (86%) diff --git a/front50-core/src/main/groovy/com/netflix/spinnaker/front50/model/application/ApplicationDAO.groovy b/front50-core/src/main/groovy/com/netflix/spinnaker/front50/model/application/ApplicationDAO.groovy index 234728b87..26b013e6a 100644 --- a/front50-core/src/main/groovy/com/netflix/spinnaker/front50/model/application/ApplicationDAO.groovy +++ b/front50-core/src/main/groovy/com/netflix/spinnaker/front50/model/application/ApplicationDAO.groovy @@ -21,7 +21,7 @@ package com.netflix.spinnaker.front50.model.application import com.netflix.spinnaker.front50.exception.NotFoundException import com.netflix.spinnaker.front50.model.ItemDAO -public interface ApplicationDAO extends ItemDAO { +public interface ApplicationDAO extends com.netflix.spinnaker.front50.model.ItemDAO { Application findByName(String name) throws NotFoundException Collection search(Map attributes) diff --git a/front50-pipelines/src/main/groovy/com/netflix/spinnaker/front50/pipeline/StrategyRepository.groovy b/front50-pipelines/src/main/groovy/com/netflix/spinnaker/front50/pipeline/StrategyRepository.groovy index 2fd624448..ec6d38963 100644 --- a/front50-pipelines/src/main/groovy/com/netflix/spinnaker/front50/pipeline/StrategyRepository.groovy +++ b/front50-pipelines/src/main/groovy/com/netflix/spinnaker/front50/pipeline/StrategyRepository.groovy @@ -144,7 +144,7 @@ class StrategyRepository implements PipelineStrategyDAO { @Override boolean isHealthy() { - return false + return true } List getPipelinesByApplication(String application) { diff --git a/front50-s3/src/main/java/com/netflix/spinnaker/front50/model/S3Support.java b/front50-s3/src/main/java/com/netflix/spinnaker/front50/model/S3Support.java index 5cf8060e3..ef9fc6d4e 100644 --- a/front50-s3/src/main/java/com/netflix/spinnaker/front50/model/S3Support.java +++ b/front50-s3/src/main/java/com/netflix/spinnaker/front50/model/S3Support.java @@ -43,6 +43,8 @@ public abstract class S3Support { private final int refreshIntervalMs; private final String bucket; + private long lastRefreshedTime; + protected final String rootFolder; protected final AtomicReference> allItemsCache = new AtomicReference<>(); @@ -81,8 +83,11 @@ public Collection all() { return allItemsCache.get().stream().collect(Collectors.toList()); } + /** + * @return Healthy if refreshed in the past 45s + */ public boolean isHealthy() { - return allItemsCache.get() != null; + return (System.currentTimeMillis() - lastRefreshedTime) < 45000 && allItemsCache.get() != null; } public T findById(String id) throws NotFoundException { @@ -95,6 +100,7 @@ public T findById(String id) throws NotFoundException { throw new IllegalStateException(e); } catch (AmazonS3Exception e) { if (e.getStatusCode() == 404) { + log.warn(String.format("No item found with id of %s", id.toLowerCase())); throw new NotFoundException(String.format("No item found with id of %s", id.toLowerCase())); } @@ -214,6 +220,7 @@ protected Set fetchAllItems(Set existingItems) { existingItemsByName.put(item.getId().toLowerCase(), item); }); + lastRefreshedTime = System.currentTimeMillis(); return existingItemsByName.values().stream().collect(Collectors.toSet()); } diff --git a/front50-web/src/main/groovy/com/netflix/spinnaker/front50/config/Front50WebConfig.groovy b/front50-web/src/main/groovy/com/netflix/spinnaker/front50/config/Front50WebConfig.groovy index 120ecb7c5..752b0fdff 100644 --- a/front50-web/src/main/groovy/com/netflix/spinnaker/front50/config/Front50WebConfig.groovy +++ b/front50-web/src/main/groovy/com/netflix/spinnaker/front50/config/Front50WebConfig.groovy @@ -17,8 +17,13 @@ package com.netflix.spinnaker.front50.config import com.netflix.spectator.api.Registry +import com.netflix.spinnaker.front50.model.application.ApplicationDAO +import com.netflix.spinnaker.front50.model.pipeline.PipelineDAO +import com.netflix.spinnaker.front50.model.pipeline.PipelineStrategyDAO +import com.netflix.spinnaker.front50.model.project.ProjectDAO import com.netflix.spinnaker.kork.web.interceptors.MetricsInterceptor import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.annotation.Bean import org.springframework.context.annotation.ComponentScan import org.springframework.context.annotation.Configuration import org.springframework.web.servlet.config.annotation.InterceptorRegistry @@ -38,4 +43,24 @@ public class Front50WebConfig extends WebMvcConfigurerAdapter { ) ) } + + @Bean + ItemDAOHealthIndicator applicationDAOHealthIndicator(ApplicationDAO applicationDAO) { + return new ItemDAOHealthIndicator(itemDAO: applicationDAO) + } + + @Bean + ItemDAOHealthIndicator projectDAOHealthIndicator(ProjectDAO projectDAO) { + return new ItemDAOHealthIndicator(itemDAO: projectDAO) + } + + @Bean + ItemDAOHealthIndicator pipelineDAOHealthIndicator(PipelineDAO pipelineDAO) { + return new ItemDAOHealthIndicator(itemDAO: pipelineDAO) + } + + @Bean + ItemDAOHealthIndicator pipelineStrategyDAOHealthIndicator(PipelineStrategyDAO pipelineStrategyDAO) { + return new ItemDAOHealthIndicator(itemDAO: pipelineStrategyDAO) + } } diff --git a/front50-core/src/main/groovy/com/netflix/spinnaker/front50/config/ApplicationDAOProviderHealthIndicator.groovy b/front50-web/src/main/groovy/com/netflix/spinnaker/front50/config/ItemDAOHealthIndicator.groovy similarity index 68% rename from front50-core/src/main/groovy/com/netflix/spinnaker/front50/config/ApplicationDAOProviderHealthIndicator.groovy rename to front50-web/src/main/groovy/com/netflix/spinnaker/front50/config/ItemDAOHealthIndicator.groovy index ce22f0476..def272ff8 100644 --- a/front50-core/src/main/groovy/com/netflix/spinnaker/front50/config/ApplicationDAOProviderHealthIndicator.groovy +++ b/front50-web/src/main/groovy/com/netflix/spinnaker/front50/config/ItemDAOHealthIndicator.groovy @@ -17,20 +17,16 @@ package com.netflix.spinnaker.front50.config -import com.netflix.spinnaker.front50.model.application.ApplicationDAO -import org.springframework.beans.factory.annotation.Autowired +import com.netflix.spinnaker.front50.model.ItemDAO import org.springframework.boot.actuate.health.Health import org.springframework.boot.actuate.health.HealthIndicator import org.springframework.scheduling.annotation.Scheduled -import org.springframework.stereotype.Component import java.util.concurrent.atomic.AtomicReference -@Component -public class ApplicationDAOProviderHealthIndicator implements HealthIndicator { +public class ItemDAOHealthIndicator implements HealthIndicator { - @Autowired - ApplicationDAO applicationDAO + ItemDAO itemDAO private final AtomicReference lastHealth = new AtomicReference<>(null) @@ -47,13 +43,13 @@ public class ApplicationDAOProviderHealthIndicator implements HealthIndicator { def healthBuilder = new Health.Builder().up() try { - if (applicationDAO.healthy) { - healthBuilder.withDetail(applicationDAO.class.simpleName, "Healthy") + if (itemDAO.healthy) { + healthBuilder.withDetail(itemDAO.class.simpleName, "Healthy") } else { - healthBuilder.down().withDetail(applicationDAO.class.simpleName, "Unhealthy") + healthBuilder.down().withDetail(itemDAO.class.simpleName, "Unhealthy") } } catch (RuntimeException e) { - healthBuilder.down().withDetail(applicationDAO.class.simpleName, "Unhealthy: `${e.message}`" as String) + healthBuilder.down().withDetail(itemDAO.class.simpleName, "Unhealthy: `${e.message}`" as String) } lastHealth.set(healthBuilder.build()) diff --git a/front50-core/src/test/groovy/com/netflix/spinnaker/front50/config/ApplicationDAOProviderHealthIndicatorSpec.groovy b/front50-web/src/test/groovy/com/netflix/spinnaker/front50/config/ItemDAOHealthIndicatorSpec.groovy similarity index 86% rename from front50-core/src/test/groovy/com/netflix/spinnaker/front50/config/ApplicationDAOProviderHealthIndicatorSpec.groovy rename to front50-web/src/test/groovy/com/netflix/spinnaker/front50/config/ItemDAOHealthIndicatorSpec.groovy index b77c117bb..9c2cd6f05 100644 --- a/front50-core/src/test/groovy/com/netflix/spinnaker/front50/config/ApplicationDAOProviderHealthIndicatorSpec.groovy +++ b/front50-web/src/test/groovy/com/netflix/spinnaker/front50/config/ItemDAOHealthIndicatorSpec.groovy @@ -22,16 +22,16 @@ import org.springframework.boot.actuate.health.Status import spock.lang.Shared import spock.lang.Specification -class ApplicationDAOProviderHealthIndicatorSpec extends Specification { +class ItemDAOHealthIndicatorSpec extends Specification { @Shared - ApplicationDAOProviderHealthIndicator healthCheck + ItemDAOHealthIndicator healthCheck @Shared ApplicationDAO dao void setup() { dao = Mock(ApplicationDAO) - healthCheck = new ApplicationDAOProviderHealthIndicator(applicationDAO: dao) + healthCheck = new ItemDAOHealthIndicator(itemDAO: dao) } void 'health check should return 5xx error if dao is not working'() {