use of io.github.resilience4j.bulkhead.ThreadPoolBulkhead in project resilience4j by resilience4j.
the class TaggedThreadPoolBulkheadMetricsPublisherTest method shouldAddMetricsForANewlyCreatedRetry.
@Test
public void shouldAddMetricsForANewlyCreatedRetry() {
ThreadPoolBulkhead newBulkhead = bulkheadRegistry.bulkhead("backendB");
assertThat(taggedBulkheadMetricsPublisher.meterIdMap).containsKeys("backendA", "backendB");
assertThat(taggedBulkheadMetricsPublisher.meterIdMap.get("backendA")).hasSize(EXPECTED_METER_COUNT);
assertThat(taggedBulkheadMetricsPublisher.meterIdMap.get("backendB")).hasSize(EXPECTED_METER_COUNT);
List<Meter> meters = meterRegistry.getMeters();
assertThat(meters).hasSize(EXPECTED_METER_COUNT * 2);
Collection<Gauge> gauges = meterRegistry.get(DEFAULT_MAX_THREAD_POOL_SIZE_METRIC_NAME).gauges();
Optional<Gauge> successful = findMeterByNamesTag(gauges, newBulkhead.getName());
assertThat(successful).isPresent();
assertThat(successful.get().value()).isEqualTo(newBulkhead.getMetrics().getMaximumThreadPoolSize());
}
use of io.github.resilience4j.bulkhead.ThreadPoolBulkhead in project resilience4j by resilience4j.
the class TaggedThreadPoolBulkheadMetrics method bindTo.
@Override
public void bindTo(MeterRegistry registry) {
for (ThreadPoolBulkhead bulkhead : bulkheadRegistry.getAllBulkheads()) {
addMetrics(registry, bulkhead);
}
bulkheadRegistry.getEventPublisher().onEntryAdded(event -> addMetrics(registry, event.getAddedEntry()));
bulkheadRegistry.getEventPublisher().onEntryRemoved(event -> removeMetrics(registry, event.getRemovedEntry().getName()));
bulkheadRegistry.getEventPublisher().onEntryReplaced(event -> {
removeMetrics(registry, event.getOldEntry().getName());
addMetrics(registry, event.getNewEntry());
});
}
use of io.github.resilience4j.bulkhead.ThreadPoolBulkhead in project resilience4j by resilience4j.
the class ThreadPoolBulkheadMetricsCollector method collect.
@Override
public List<MetricFamilySamples> collect() {
GaugeMetricFamily availableCallsFamily = new GaugeMetricFamily(names.getCurrentThreadPoolSizeName(), "The number of currently used bulkhead threads", LabelNames.NAME);
GaugeMetricFamily maxAllowedCallsFamily = new GaugeMetricFamily(names.getAvailableQueueCapacityName(), "The number of available bulkhead queue slots", LabelNames.NAME);
for (ThreadPoolBulkhead bulkhead : bulkheadRegistry.getAllBulkheads()) {
List<String> labelValues = singletonList(bulkhead.getName());
availableCallsFamily.addMetric(labelValues, bulkhead.getMetrics().getThreadPoolSize());
maxAllowedCallsFamily.addMetric(labelValues, bulkhead.getMetrics().getRemainingQueueCapacity());
}
return asList(availableCallsFamily, maxAllowedCallsFamily);
}
use of io.github.resilience4j.bulkhead.ThreadPoolBulkhead in project resilience4j by resilience4j.
the class DecoratorsTest method testDecorateSupplierWithBulkheadFullExceptionFallback.
@Test
public void testDecorateSupplierWithBulkheadFullExceptionFallback() throws ExecutionException, InterruptedException {
ThreadPoolBulkhead bulkhead = ThreadPoolBulkhead.ofDefaults("helloBackend");
ThreadPoolBulkhead bulkheadMock = spy(bulkhead);
given(bulkheadMock.submit(any(Callable.class))).willThrow(BulkheadFullException.createBulkheadFullException(bulkhead));
CompletionStage<String> completionStage = Decorators.ofSupplier(() -> helloWorldService.returnHelloWorld()).withThreadPoolBulkhead(bulkheadMock).withFallback(BulkheadFullException.class, (e) -> "Fallback").get();
String result = completionStage.toCompletableFuture().get();
assertThat(result).isEqualTo("Fallback");
}
use of io.github.resilience4j.bulkhead.ThreadPoolBulkhead in project resilience4j by resilience4j.
the class DecoratorsTest method shouldThrowTimeoutExceptionAndPropagateContext.
@Test
public void shouldThrowTimeoutExceptionAndPropagateContext() {
TimeLimiter timeLimiter = TimeLimiter.of("helloBackend", TimeLimiterConfig.custom().timeoutDuration(Duration.ofMillis(100)).build());
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("helloBackend");
ThreadPoolBulkhead bulkhead = ThreadPoolBulkhead.ofDefaults("helloBackend");
TestThreadLocalContextPropagatorWithHolder propagator = new TestThreadLocalContextPropagatorWithHolder();
TestThreadLocalContextHolder.put("ValueShouldCrossThreadBoundary");
ContextAwareScheduledThreadPoolExecutor scheduledThreadPool = ContextAwareScheduledThreadPoolExecutor.newScheduledThreadPool().corePoolSize(1).contextPropagators(propagator).build();
CompletionStage<String> completionStage = Decorators.ofCallable(() -> {
assertThat(Thread.currentThread().getName()).isEqualTo("bulkhead-helloBackend-1");
Thread.sleep(1000);
return "Bla";
}).withThreadPoolBulkhead(bulkhead).withTimeLimiter(timeLimiter, scheduledThreadPool).withCircuitBreaker(circuitBreaker).get();
final CompletableFuture<String> completableFuture = completionStage.toCompletableFuture().exceptionally(throwable -> {
if (throwable != null) {
assertThat(Thread.currentThread().getName()).isEqualTo("ContextAwareScheduledThreadPool-1");
assertThat(TestThreadLocalContextHolder.get().get()).isEqualTo("ValueShouldCrossThreadBoundary");
return (String) TestThreadLocalContextHolder.get().orElse(null);
}
return null;
});
waitAtMost(2, TimeUnit.SECONDS).until(matches(() -> assertThat(completableFuture).isCompletedWithValue("ValueShouldCrossThreadBoundary")));
CircuitBreaker.Metrics metrics = circuitBreaker.getMetrics();
assertThat(metrics.getNumberOfBufferedCalls()).isEqualTo(1);
assertThat(metrics.getNumberOfFailedCalls()).isEqualTo(1);
}
Aggregations