[#39] Initial approach to Hystrix concurrency strategy
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
package org.springframework.cloud.sleuth.instrument.hystrix;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.instrument.TraceCallable;
|
||||
|
||||
import com.netflix.hystrix.strategy.HystrixPlugins;
|
||||
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
|
||||
|
||||
public class SleuthHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
|
||||
|
||||
private final TraceManager traceManager;
|
||||
|
||||
public SleuthHystrixConcurrencyStrategy(TraceManager traceManager) {
|
||||
this.traceManager = traceManager;
|
||||
HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Callable<T> wrapCallable(Callable<T> callable) {
|
||||
return new TraceCallable<>(traceManager, callable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.springframework.cloud.sleuth.instrument.hystrix;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.netflix.hystrix.HystrixCommand;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(HystrixCommand.class)
|
||||
@ConditionalOnProperty(value = "spring.sleuth.hystrix.strategy.enabled", matchIfMissing = true)
|
||||
public class SleuthHystrixConfiguration {
|
||||
|
||||
@Bean SleuthHystrixConcurrencyStrategy sleuthHystrixConcurrencyStrategy(TraceManager traceManager) {
|
||||
return new SleuthHystrixConcurrencyStrategy(traceManager);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ org.springframework.cloud.sleuth.log.SleuthLogAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.integration.TraceSpringIntegrationAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.async.AsyncCustomAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.async.AsyncDefaultAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.hystrix.SleuthHystrixConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.scheduling.TraceSchedulingAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.client.TraceWebClientAutoConfiguration,\
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
package org.springframework.cloud.sleuth.instrument.hystrix;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.instrument.DefaultTestAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.trace.TraceContextHolder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.jayway.awaitility.Awaitility;
|
||||
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = {
|
||||
JavanicaITest.JavanicaITestConfiguration.class })
|
||||
public class JavanicaITest {
|
||||
|
||||
@Autowired JavanicaClass javanicaClass;
|
||||
@Autowired JavanicaDelegation javanicaDelegation;
|
||||
@Autowired TraceManager traceManager;
|
||||
|
||||
@Test
|
||||
public void should_set_span_on_an_hystrix_command_annotated_method() {
|
||||
final Span span = givenASpanInCurrentThread();
|
||||
|
||||
whenHystrixCommandGetsExecutedViaJavanica();
|
||||
|
||||
thenSpanPutInTheAsyncThreadIsSameAs(span);
|
||||
}
|
||||
|
||||
private Span givenASpanInCurrentThread() {
|
||||
Span span = this.traceManager.startSpan("existing").getSpan();
|
||||
this.traceManager.continueSpan(span);
|
||||
return span;
|
||||
}
|
||||
|
||||
private void whenHystrixCommandGetsExecutedViaJavanica() {
|
||||
this.javanicaDelegation.doSthThatDelegatesToJavanica();
|
||||
}
|
||||
|
||||
private void thenSpanPutInTheAsyncThreadIsSameAs(final Span span) {
|
||||
Awaitility.await().until(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
then(span.getTraceId()).isNotNull()
|
||||
.isEqualTo(javanicaClass.getTraceId());
|
||||
then(span.getName())
|
||||
.isNotEqualTo(javanicaClass.getSpanName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanTrace() {
|
||||
TraceContextHolder.removeCurrentTrace();
|
||||
}
|
||||
|
||||
@DefaultTestAutoConfiguration
|
||||
@EnableHystrix
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||
@Configuration
|
||||
public static class JavanicaITestConfiguration {
|
||||
|
||||
@Bean
|
||||
JavanicaClass javanicaClass() {
|
||||
return new JavanicaClass();
|
||||
}
|
||||
|
||||
@Bean
|
||||
JavanicaDelegation javanicaDelegation() {
|
||||
return new JavanicaDelegation(javanicaClass());
|
||||
}
|
||||
}
|
||||
|
||||
public static class JavanicaDelegation {
|
||||
|
||||
private final JavanicaClass javanicaClass;
|
||||
|
||||
public JavanicaDelegation(JavanicaClass javanicaClass) {
|
||||
this.javanicaClass = javanicaClass;
|
||||
}
|
||||
|
||||
public void doSthThatDelegatesToJavanica() {
|
||||
this.javanicaClass.doSth();
|
||||
}
|
||||
}
|
||||
|
||||
public static class JavanicaClass {
|
||||
|
||||
AtomicReference<Span> span;
|
||||
|
||||
@HystrixCommand
|
||||
public void doSth() {
|
||||
this.span = new AtomicReference<>(TraceContextHolder.getCurrentSpan());
|
||||
}
|
||||
|
||||
public String getTraceId() {
|
||||
if (this.span == null || this.span.get() == null || (this.span.get() != null
|
||||
&& this.span.get().getTraceId() == null)) {
|
||||
return null;
|
||||
}
|
||||
return this.span.get().getTraceId();
|
||||
}
|
||||
|
||||
public String getSpanName() {
|
||||
if (this.span == null
|
||||
|| (this.span.get() != null && this.span.get().getName() == null)) {
|
||||
return null;
|
||||
}
|
||||
return this.span.get().getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,15 +25,12 @@ import com.jayway.awaitility.Awaitility;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = {
|
||||
TraceAsyncITest.CorrelationIdAsyncSpecConfiguration.class })
|
||||
TraceAsyncITest.TraceAsyncITestConfiguration.class })
|
||||
public class TraceAsyncITest {
|
||||
|
||||
@Autowired
|
||||
AsyncClass asyncClass;
|
||||
@Autowired
|
||||
AsyncDelegation asyncDelegation;
|
||||
@Autowired
|
||||
TraceManager traceManager;
|
||||
@Autowired AsyncClass asyncClass;
|
||||
@Autowired AsyncDelegation asyncDelegation;
|
||||
@Autowired TraceManager traceManager;
|
||||
|
||||
@Test
|
||||
public void should_set_span_on_an_async_annotated_method() {
|
||||
@@ -75,7 +72,7 @@ public class TraceAsyncITest {
|
||||
@EnableAsync
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||
@Configuration
|
||||
public static class CorrelationIdAsyncSpecConfiguration {
|
||||
public static class TraceAsyncITestConfiguration {
|
||||
|
||||
@Bean
|
||||
AsyncClass asyncClass() {
|
||||
|
||||
Reference in New Issue
Block a user