[#39] Initial approach to Hystrix concurrency strategy

This commit is contained in:
Marcin Grzejszczak
2015-12-23 18:08:09 +01:00
parent aaa00a9754
commit 6ecfbca6ed
5 changed files with 174 additions and 8 deletions

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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,\

View File

@@ -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();
}
}
}

View File

@@ -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() {