Add passthrough mode to HystrixConcurrencyStrategy (#1433)
Add passthrough mode to HystrixConcurrencyStrategy. Fixes #1431.
This commit is contained in:
committed by
Marcin Grzejszczak
parent
aa1d0830ba
commit
33cab91195
@@ -1028,6 +1028,7 @@ That way, you ensure that a new span is created and closed for each execution.
|
||||
|
||||
We register a custom https://github.com/Netflix/Hystrix/wiki/Plugins#concurrencystrategy[`HystrixConcurrencyStrategy`] called `TraceCallable` that wraps all `Callable` instances in their Sleuth representative.
|
||||
The strategy either starts or continues a span, depending on whether tracing was already going on before the Hystrix command was called.
|
||||
Optionally, you can set `spring.sleuth.hystrix.strategy.passthrough` to `true` to just propagate the trace context to the Hystrix execution thread if you don't wish to start a new span.
|
||||
To disable the custom Hystrix Concurrency Strategy, set the `spring.sleuth.hystrix.strategy.enabled` to `false`.
|
||||
|
||||
==== Manual Command setting
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -34,8 +35,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
* {@link com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy}.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.0.0
|
||||
* @see SleuthHystrixConcurrencyStrategy
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter(TraceAutoConfiguration.class)
|
||||
@@ -43,12 +44,14 @@ import org.springframework.context.annotation.Configuration;
|
||||
@ConditionalOnBean(Tracing.class)
|
||||
@ConditionalOnProperty(value = "spring.sleuth.hystrix.strategy.enabled",
|
||||
matchIfMissing = true)
|
||||
@EnableConfigurationProperties(SleuthHystrixConcurrencyStrategyProperties.class)
|
||||
public class SleuthHystrixAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
SleuthHystrixConcurrencyStrategy sleuthHystrixConcurrencyStrategy(Tracing tracing,
|
||||
SpanNamer spanNamer) {
|
||||
return new SleuthHystrixConcurrencyStrategy(tracing, spanNamer);
|
||||
SpanNamer spanNamer, SleuthHystrixConcurrencyStrategyProperties properties) {
|
||||
return new SleuthHystrixConcurrencyStrategy(tracing, spanNamer,
|
||||
properties.isPassthrough());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -60,9 +60,17 @@ public class SleuthHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy
|
||||
|
||||
private HystrixConcurrencyStrategy delegate;
|
||||
|
||||
private boolean passthrough;
|
||||
|
||||
public SleuthHystrixConcurrencyStrategy(Tracing tracing, SpanNamer spanNamer) {
|
||||
this(tracing, spanNamer, false);
|
||||
}
|
||||
|
||||
public SleuthHystrixConcurrencyStrategy(Tracing tracing, SpanNamer spanNamer,
|
||||
boolean passthrough) {
|
||||
this.tracing = tracing;
|
||||
this.spanNamer = spanNamer;
|
||||
this.passthrough = passthrough;
|
||||
try {
|
||||
this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
|
||||
if (this.delegate instanceof SleuthHystrixConcurrencyStrategy) {
|
||||
@@ -77,7 +85,7 @@ public class SleuthHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy
|
||||
.getMetricsPublisher();
|
||||
HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance()
|
||||
.getPropertiesStrategy();
|
||||
logCurrentStateOfHysrixPlugins(eventNotifier, metricsPublisher,
|
||||
logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher,
|
||||
propertiesStrategy);
|
||||
HystrixPlugins.reset();
|
||||
HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
|
||||
@@ -92,7 +100,7 @@ public class SleuthHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy
|
||||
}
|
||||
}
|
||||
|
||||
private void logCurrentStateOfHysrixPlugins(HystrixEventNotifier eventNotifier,
|
||||
private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
|
||||
HystrixMetricsPublisher metricsPublisher,
|
||||
HystrixPropertiesStrategy propertiesStrategy) {
|
||||
if (log.isDebugEnabled()) {
|
||||
@@ -109,13 +117,21 @@ public class SleuthHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy
|
||||
if (callable instanceof TraceCallable) {
|
||||
return callable;
|
||||
}
|
||||
|
||||
Callable<T> wrappedCallable = this.delegate != null
|
||||
? this.delegate.wrapCallable(callable) : callable;
|
||||
|
||||
if (wrappedCallable instanceof TraceCallable) {
|
||||
return wrappedCallable;
|
||||
}
|
||||
return new TraceCallable<>(this.tracing, this.spanNamer, wrappedCallable,
|
||||
HYSTRIX_COMPONENT);
|
||||
|
||||
if (passthrough) {
|
||||
return this.tracing.currentTraceContext().wrap(callable);
|
||||
}
|
||||
else {
|
||||
return new TraceCallable<>(this.tracing, this.spanNamer, wrappedCallable,
|
||||
HYSTRIX_COMPONENT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.cloud.sleuth.instrument.hystrix;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Sleuth Hystrix settings.
|
||||
*
|
||||
* @author Daniel Albuquerque
|
||||
*/
|
||||
@ConfigurationProperties("spring.sleuth.hystrix.strategy")
|
||||
public class SleuthHystrixConcurrencyStrategyProperties {
|
||||
|
||||
/**
|
||||
* Enable custom HystrixConcurrencyStrategy that wraps all Callable instances into
|
||||
* their Sleuth representative - the TraceCallable.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* When enabled the tracing information is passed to the Hystrix execution threads but
|
||||
* spans are not created for each execution.
|
||||
*/
|
||||
private boolean passthrough = false;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isPassthrough() {
|
||||
return passthrough;
|
||||
}
|
||||
|
||||
public void setPassthrough(boolean passthrough) {
|
||||
this.passthrough = passthrough;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,12 +24,6 @@
|
||||
"description": "Enable default AsyncConfigurer.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "spring.sleuth.hystrix.strategy.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Enable custom HystrixConcurrencyStrategy that wraps all Callable instances into their Sleuth representative - the TraceCallable.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "spring.sleuth.feign.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
|
||||
@@ -21,8 +21,10 @@ import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import brave.Tracing;
|
||||
import brave.propagation.CurrentTraceContext;
|
||||
import brave.propagation.StrictScopeDecorator;
|
||||
import brave.propagation.ThreadLocalCurrentTraceContext;
|
||||
import brave.propagation.TraceContext;
|
||||
import com.netflix.hystrix.HystrixThreadPoolKey;
|
||||
import com.netflix.hystrix.HystrixThreadPoolProperties;
|
||||
import com.netflix.hystrix.strategy.HystrixPlugins;
|
||||
@@ -123,6 +125,25 @@ public class SleuthHystrixConcurrencyStrategyTest {
|
||||
then(this.reporter.getSpans()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_propagate_trace_context_when_passthrough_is_enabled()
|
||||
throws Exception {
|
||||
SleuthHystrixConcurrencyStrategy strategy = new SleuthHystrixConcurrencyStrategy(
|
||||
this.tracing, new DefaultSpanNamer(), true);
|
||||
|
||||
TraceContext traceContext = TraceContext.newBuilder().traceId(123L).spanId(456L)
|
||||
.build();
|
||||
CurrentTraceContext.Scope scope = tracing.currentTraceContext()
|
||||
.newScope(traceContext);
|
||||
|
||||
Callable<TraceContext> callable = strategy
|
||||
.wrapCallable(() -> tracing.currentTraceContext().get());
|
||||
|
||||
then(callable).isNotInstanceOf(TraceCallable.class);
|
||||
then(callable.call()).isEqualTo(traceContext);
|
||||
scope.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_delegate_work_to_custom_hystrix_concurrency_strategy()
|
||||
throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user