package com.yammer.breakerbox.service.resources; import com.codahale.metrics.annotation.Timed; import com.google.common.base.Optional; import com.netflix.hystrix.HystrixCommandProperties; import com.yammer.breakerbox.store.BreakerboxStore; import com.yammer.breakerbox.store.DependencyId; import com.yammer.breakerbox.store.ServiceId; import com.yammer.breakerbox.store.model.DependencyModel; import com.yammer.breakerbox.store.model.ServiceModel; import com.yammer.dropwizard.authenticator.User; import com.yammer.tenacity.core.config.CircuitBreakerConfiguration; import com.yammer.tenacity.core.config.SemaphoreConfiguration; import com.yammer.tenacity.core.config.TenacityConfiguration; import com.yammer.tenacity.core.config.ThreadPoolConfiguration; import io.dropwizard.auth.Auth; import org.joda.time.DateTime; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.net.URI; @Path("/configure/{service}") public class ConfigureResource { private final BreakerboxStore breakerboxStore; public ConfigureResource(BreakerboxStore breakerboxStore) { this.breakerboxStore = breakerboxStore; } @GET @Timed @Produces(MediaType.APPLICATION_JSON) @Path("/{dependency}") public TenacityConfiguration get(@PathParam("service") String serviceName, @PathParam("dependency") String dependencyName) { final Optional<DependencyModel> entity = breakerboxStore.retrieveLatest(DependencyId.from(dependencyName), ServiceId.from(serviceName)); if (entity.isPresent()) { return entity.get().getTenacityConfiguration(); } throw new WebApplicationException(); } @POST @Timed @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Path("/{dependency}") public Response configure(@Auth User user, @PathParam("service") String serviceName, @PathParam("dependency") String dependencyName, @FormParam("executionTimeout") Integer executionTimeout, @FormParam("requestVolumeThreshold") Integer requestVolumeThreshold, @FormParam("errorThresholdPercentage") Integer errorThresholdPercentage, @FormParam("sleepWindow") Integer sleepWindow, @FormParam("circuitBreakerstatisticalWindow") Integer circuitBreakerstatisticalWindow, @FormParam("circuitBreakerStatisticalWindowBuckets") Integer circuitBreakerStatisticalWindowBuckets, @FormParam("threadPoolCoreSize") Integer threadPoolCoreSize, @FormParam("keepAliveMinutes") Integer keepAliveMinutes, @FormParam("maxQueueSize") Integer maxQueueSize, @FormParam("queueSizeRejectionThreshold") Integer queueSizeRejectionThreshold, @FormParam("threadpoolStatisticalWindow") Integer threadpoolStatisticalWindow, @FormParam("threadpoolStatisticalWindowBuckets") Integer threadpoolStatisticalWindowBuckets, @FormParam("semaphoreMaxConcurrentRequests") Integer semaphoreMaxConcurrentRequests, @FormParam("semaphoreFallbackMaxConcurrentRequests") Integer semaphoreFallbackMaxConcurrentRequests, @FormParam("executionIsolationStrategy") HystrixCommandProperties.ExecutionIsolationStrategy executionIsolationStrategy) { final TenacityConfiguration tenacityConfiguration = new TenacityConfiguration( new ThreadPoolConfiguration( threadPoolCoreSize, keepAliveMinutes, maxQueueSize, queueSizeRejectionThreshold, threadpoolStatisticalWindow, threadpoolStatisticalWindowBuckets), new CircuitBreakerConfiguration( requestVolumeThreshold, sleepWindow, errorThresholdPercentage, circuitBreakerstatisticalWindow, circuitBreakerStatisticalWindowBuckets), new SemaphoreConfiguration( semaphoreMaxConcurrentRequests, semaphoreFallbackMaxConcurrentRequests), executionTimeout, executionIsolationStrategy); final ServiceId serviceId = ServiceId.from(serviceName); final DependencyId dependencyId = DependencyId.from(dependencyName); if (breakerboxStore.store(new ServiceModel(serviceId, dependencyId)) && breakerboxStore.store(new DependencyModel(dependencyId, DateTime.now(), tenacityConfiguration, user.getName(), serviceId))) { return Response .created(URI.create(String.format("/configuration/%s/%s", serviceName, dependencyName))) .entity(tenacityConfiguration) .build(); } else { return Response.serverError().build(); } } }