Skip to content

Commit

Permalink
Issue ReactiveX#179: Migrated Spring Boot 2 Actuator endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert Winkler committed Mar 16, 2018
1 parent 204609f commit 3e55b50
Show file tree
Hide file tree
Showing 15 changed files with 144 additions and 398 deletions.
2 changes: 1 addition & 1 deletion libraries.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ ext {
assertjVersion = '3.6.2'
logbackVersion = '0.9.26'
mockitoVersion = '2.15.0'
powermockVersion = '1.7.0'
powermockVersion = '2.0.0-beta.5'
jcacheVersion = '1.0.0'
awaitilityVersion = '1.7.0'
metricsVersion = '3.2.5'
Expand Down
3 changes: 1 addition & 2 deletions resilience4j-spring-boot2/build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
dependencies {
compile ( libraries.spring_boot2_aop )
compile ( libraries.spring_boot2_actuator )
compile ( libraries.spring_boot2_web )
compile ( libraries.spring_reactor )
compile project(':resilience4j-micrometer')
compile project(':resilience4j-circuitbreaker')
compile project(':resilience4j-ratelimiter')
compile project(':resilience4j-consumer')
testCompile ( libraries.spring_boot2_test )
testCompile ( libraries.spring_boot2_web )
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package io.github.resilience4j.circuitbreaker.autoconfigure;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
Expand All @@ -26,6 +27,8 @@
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.circuitbreaker.event.CircuitBreakerEvent;
import io.github.resilience4j.circuitbreaker.internal.InMemoryCircuitBreakerRegistry;
import io.github.resilience4j.circuitbreaker.monitoring.endpoint.CircuitBreakerEndpoint;
import io.github.resilience4j.circuitbreaker.monitoring.endpoint.CircuitBreakerEventsEndpoint;
import io.github.resilience4j.circuitbreaker.monitoring.health.CircuitBreakerHealthIndicator;
import io.github.resilience4j.consumer.DefaultEventConsumerRegistry;
import io.github.resilience4j.consumer.EventConsumerRegistry;
Expand Down Expand Up @@ -62,6 +65,19 @@ public CircuitBreakerRegistry circuitBreakerRegistry(CircuitBreakerProperties ci
return circuitBreakerRegistry;
}

@Bean
@ConditionalOnEnabledEndpoint
public CircuitBreakerEndpoint circuitBreakerEndpoint(CircuitBreakerRegistry circuitBreakerRegistry) {
return new CircuitBreakerEndpoint(circuitBreakerRegistry);
}

@Bean
@ConditionalOnEnabledEndpoint
public CircuitBreakerEventsEndpoint circuitBreakerEventsEndpoint(EventConsumerRegistry<CircuitBreakerEvent> eventConsumerRegistry,
CircuitBreakerRegistry circuitBreakerRegistry) {
return new CircuitBreakerEventsEndpoint(eventConsumerRegistry, circuitBreakerRegistry);
}

@Bean
public CircuitBreakerAspect circuitBreakerAspect(CircuitBreakerProperties circuitBreakerProperties,
CircuitBreakerRegistry circuitBreakerRegistry) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2017 Robert Winkler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.resilience4j.circuitbreaker.monitoring.endpoint;


import java.util.List;

import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;


@WebEndpoint(id = "circuitbreaker")
public class CircuitBreakerEndpoint {

private final CircuitBreakerRegistry circuitBreakerRegistry;

public CircuitBreakerEndpoint(CircuitBreakerRegistry circuitBreakerRegistry) {
this.circuitBreakerRegistry = circuitBreakerRegistry;
}

@ReadOperation
public CircuitBreakerEndpointResponse getAllCircuitBreakers() {
List<String> circuitBreakers = circuitBreakerRegistry.getAllCircuitBreakers()
.map(CircuitBreaker::getName).sorted().toJavaList();
return new CircuitBreakerEndpointResponse(circuitBreakers);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,19 @@
package io.github.resilience4j.circuitbreaker.monitoring.endpoint;


import static io.github.resilience4j.adapter.ReactorAdapter.toFlux;

import java.util.Comparator;
import java.util.List;

import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.circuitbreaker.event.CircuitBreakerEvent;
import io.github.resilience4j.consumer.CircularEventConsumer;
import io.github.resilience4j.consumer.EventConsumerRegistry;
import io.vavr.collection.Seq;
import reactor.core.publisher.Flux;


@RestController
@WebEndpoint(id = "circuitbreaker")
@RequestMapping(value = "circuitbreaker", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@WebEndpoint(id = "circuitbreaker-events")
public class CircuitBreakerEventsEndpoint {

private static final String MEDIA_TYPE_TEXT_EVENT_STREAM = "text/event-stream";
Expand All @@ -54,67 +41,28 @@ public CircuitBreakerEventsEndpoint(EventConsumerRegistry<CircuitBreakerEvent> e
this.circuitBreakerRegistry = circuitBreakerRegistry;
}

@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public CircuitBreakerEndpointResponse getAllCircuitBreakers() {
List<String> circuitBreakers = circuitBreakerRegistry.getAllCircuitBreakers()
.map(CircuitBreaker::getName).sorted().toJavaList();
return new CircuitBreakerEndpointResponse(circuitBreakers);
}

@RequestMapping(value = "events", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
@ReadOperation
public CircuitBreakerEventsEndpointResponse getAllCircuitBreakerEvents() {
return new CircuitBreakerEventsEndpointResponse(eventConsumerRegistry.getAllEventConsumer()
.flatMap(CircularEventConsumer::getBufferedEvents)
.sorted(Comparator.comparing(CircuitBreakerEvent::getCreationTime))
.map(CircuitBreakerEventDTOFactory::createCircuitBreakerEventDTO).toJavaList());
}

@RequestMapping(value = "stream/events", produces = MEDIA_TYPE_TEXT_EVENT_STREAM)
public SseEmitter getAllCircuitBreakerEventsStream() {
Seq<Flux<CircuitBreakerEvent>> eventStreams = circuitBreakerRegistry.getAllCircuitBreakers()
.map(circuitBreaker -> toFlux(circuitBreaker.getEventPublisher()));
return CircuitBreakerEventEmitter.createSseEmitter(Flux.merge(eventStreams));
}

@RequestMapping(value = "events/{circuitBreakerName}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public CircuitBreakerEventsEndpointResponse getEventsFilteredByCircuitBreakerName(@PathVariable("circuitBreakerName") String circuitBreakerName) {
@ReadOperation
public CircuitBreakerEventsEndpointResponse getEventsFilteredByCircuitBreakerName(@Selector String circuitBreakerName) {
return new CircuitBreakerEventsEndpointResponse(eventConsumerRegistry.getEventConsumer(circuitBreakerName).getBufferedEvents()
.filter(event -> event.getCircuitBreakerName().equals(circuitBreakerName))
.map(CircuitBreakerEventDTOFactory::createCircuitBreakerEventDTO).toJavaList());
}

@RequestMapping(value = "stream/events/{circuitBreakerName}", produces = MEDIA_TYPE_TEXT_EVENT_STREAM)
public SseEmitter getEventsStreamFilteredByCircuitBreakerName(@PathVariable("circuitBreakerName") String circuitBreakerName) {
CircuitBreaker circuitBreaker = circuitBreakerRegistry.getAllCircuitBreakers()
.find(cb -> cb.getName().equals(circuitBreakerName))
.getOrElseThrow(() ->
new IllegalArgumentException(String.format("circuit breaker with name %s not found", circuitBreakerName)));
return CircuitBreakerEventEmitter.createSseEmitter(toFlux(circuitBreaker.getEventPublisher()));
}

@RequestMapping(value = "events/{circuitBreakerName}/{eventType}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public CircuitBreakerEventsEndpointResponse getEventsFilteredByCircuitBreakerNameAndEventType(@PathVariable("circuitBreakerName") String circuitBreakerName,
@PathVariable("eventType") String eventType) {
@ReadOperation
public CircuitBreakerEventsEndpointResponse getEventsFilteredByCircuitBreakerNameAndEventType(@Selector String circuitBreakerName,
@Selector String eventType) {
return new CircuitBreakerEventsEndpointResponse(eventConsumerRegistry.getEventConsumer(circuitBreakerName).getBufferedEvents()
.filter(event -> event.getCircuitBreakerName().equals(circuitBreakerName))
.filter(event -> event.getEventType() == CircuitBreakerEvent.Type.valueOf(eventType.toUpperCase()))
.map(CircuitBreakerEventDTOFactory::createCircuitBreakerEventDTO).toJavaList());
}

@RequestMapping(value = "stream/events/{circuitBreakerName}/{eventType}", produces = MEDIA_TYPE_TEXT_EVENT_STREAM)
public SseEmitter getEventsStreamFilteredByCircuitBreakerNameAndEventType(@PathVariable("circuitBreakerName") String circuitBreakerName,
@PathVariable("eventType") String eventType) {
CircuitBreaker circuitBreaker = circuitBreakerRegistry.getAllCircuitBreakers()
.find(cb -> cb.getName().equals(circuitBreakerName))
.getOrElseThrow(() ->
new IllegalArgumentException(String.format("circuit breaker with name %s not found", circuitBreakerName)));
Flux<CircuitBreakerEvent> eventStream = toFlux(circuitBreaker.getEventPublisher())
.filter(event -> event.getEventType() == CircuitBreakerEvent.Type.valueOf(eventType.toUpperCase()));
return CircuitBreakerEventEmitter.createSseEmitter(eventStream);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
Expand All @@ -33,6 +34,8 @@
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.github.resilience4j.ratelimiter.event.RateLimiterEvent;
import io.github.resilience4j.ratelimiter.internal.InMemoryRateLimiterRegistry;
import io.github.resilience4j.ratelimiter.monitoring.endpoint.RateLimiterEndpoint;
import io.github.resilience4j.ratelimiter.monitoring.endpoint.RateLimiterEventsEndpoint;
import io.github.resilience4j.ratelimiter.monitoring.health.RateLimiterHealthIndicator;

/**
Expand Down Expand Up @@ -65,6 +68,19 @@ public RateLimiterRegistry rateLimiterRegistry(RateLimiterProperties rateLimiter
return rateLimiterRegistry;
}

@Bean
@ConditionalOnEnabledEndpoint
public RateLimiterEndpoint rateLimiterEndpoint(RateLimiterRegistry rateLimiterRegistry) {
return new RateLimiterEndpoint(rateLimiterRegistry);
}

@Bean
@ConditionalOnEnabledEndpoint
public RateLimiterEventsEndpoint rateLimiterEventsEndpoint(EventConsumerRegistry<RateLimiterEvent> eventConsumerRegistry,
RateLimiterRegistry rateLimiterRegistry) {
return new RateLimiterEventsEndpoint(eventConsumerRegistry, rateLimiterRegistry);
}

@Bean
public RateLimiterAspect rateLimiterAspect(RateLimiterProperties rateLimiterProperties, RateLimiterRegistry rateLimiterRegistry) {
return new RateLimiterAspect(rateLimiterRegistry, rateLimiterProperties);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2017 Bohdan Storozhuk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.resilience4j.ratelimiter.monitoring.endpoint;

import java.util.List;

import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;

import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.github.resilience4j.ratelimiter.monitoring.model.RateLimiterEndpointResponse;

@WebEndpoint(id = "ratelimiter")
public class RateLimiterEndpoint {

private final RateLimiterRegistry rateLimiterRegistry;

public RateLimiterEndpoint(RateLimiterRegistry rateLimiterRegistry) {
this.rateLimiterRegistry = rateLimiterRegistry;
}

@ReadOperation
public RateLimiterEndpointResponse getAllRateLimiters() {
List<String> names = rateLimiterRegistry.getAllRateLimiters()
.map(RateLimiter::getName).sorted().toJavaList();
return new RateLimiterEndpointResponse(names);
}
}
Loading

0 comments on commit 3e55b50

Please sign in to comment.