Wrapping ExecutorService in its own representation

without this change ExecutorService was treated as an Executor and wrapped in the Executor bean. Due to this the bean was missing / bean of invalid type was registered.
with this change we do not wrap ExecutorService with a Executor bean, instead we wrap it in a TraceableExecutorService representation.

fixes #445
This commit is contained in:
Marcin Grzejszczak
2016-11-08 15:05:06 +01:00
parent 840d30dd33
commit 9ab37c34fa
3 changed files with 72 additions and 17 deletions

View File

@@ -18,6 +18,7 @@ package org.springframework.cloud.sleuth.instrument.async;
import java.lang.invoke.MethodHandles;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -48,8 +49,11 @@ class TraceExecutorBeanPostProcessor implements BeanPostProcessor {
if (bean instanceof ThreadPoolTaskExecutor && !(bean instanceof TaskScheduler) &&
!(bean instanceof LazyTraceThreadPoolTaskExecutor)) {
return new LazyTraceThreadPoolTaskExecutor(this.beanFactory, (ThreadPoolTaskExecutor) bean);
} else if (bean instanceof Executor && !(bean instanceof TaskScheduler) && !(bean instanceof LazyTraceExecutor)) {
} else if (bean instanceof Executor && !(bean instanceof ExecutorService) &&
!(bean instanceof TaskScheduler) && !(bean instanceof LazyTraceExecutor)) {
return new LazyTraceExecutor(this.beanFactory, (Executor) bean);
} else if (bean instanceof ExecutorService) {
return new TraceableExecutorService(this.beanFactory, (ExecutorService) bean);
}
return bean;
}

View File

@@ -25,6 +25,7 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.TraceKeys;
import org.springframework.cloud.sleuth.Tracer;
@@ -36,17 +37,24 @@ import org.springframework.cloud.sleuth.Tracer;
* @since 1.0.0
*/
public class TraceableExecutorService implements ExecutorService {
final ExecutorService delegate;
final Tracer tracer;
ExecutorService delegate;
Tracer tracer;
private final String spanName;
final TraceKeys traceKeys;
final SpanNamer spanNamer;
TraceKeys traceKeys;
SpanNamer spanNamer;
BeanFactory beanFactory;
public TraceableExecutorService(final ExecutorService delegate, final Tracer tracer,
TraceKeys traceKeys, SpanNamer spanNamer) {
this(delegate, tracer, traceKeys, spanNamer, null);
}
public TraceableExecutorService(BeanFactory beanFactory, final ExecutorService delegate) {
this.delegate = delegate;
this.beanFactory = beanFactory;
this.spanName = null;
}
public TraceableExecutorService(final ExecutorService delegate, final Tracer tracer,
TraceKeys traceKeys, SpanNamer spanNamer, String spanName) {
this.delegate = delegate;
@@ -58,8 +66,8 @@ public class TraceableExecutorService implements ExecutorService {
@Override
public void execute(Runnable command) {
final Runnable r = new LocalComponentTraceRunnable(this.tracer, this.traceKeys,
this.spanNamer, command, this.spanName);
final Runnable r = new LocalComponentTraceRunnable(tracer(), traceKeys(),
spanNamer(), command, this.spanName);
this.delegate.execute(r);
}
@@ -90,22 +98,22 @@ public class TraceableExecutorService implements ExecutorService {
@Override
public <T> Future<T> submit(Callable<T> task) {
Callable<T> c = new LocalComponentTraceCallable<>(this.tracer, this.traceKeys,
this.spanNamer, this.spanName, task);
Callable<T> c = new LocalComponentTraceCallable<>(tracer(), traceKeys(),
spanNamer(), this.spanName, task);
return this.delegate.submit(c);
}
@Override
public <T> Future<T> submit(Runnable task, T result) {
Runnable r = new LocalComponentTraceRunnable(this.tracer, this.traceKeys,
this.spanNamer, task, this.spanName);
Runnable r = new LocalComponentTraceRunnable(tracer(), traceKeys(),
spanNamer(), task, this.spanName);
return this.delegate.submit(r, result);
}
@Override
public Future<?> submit(Runnable task) {
Runnable r = new LocalComponentTraceRunnable(this.tracer, this.traceKeys,
this.spanNamer, task, this.spanName);
Runnable r = new LocalComponentTraceRunnable(tracer(), traceKeys(),
spanNamer(), task, this.spanName);
return this.delegate.submit(r);
}
@@ -135,11 +143,32 @@ public class TraceableExecutorService implements ExecutorService {
List<Callable<T>> ts = new ArrayList<>();
for (Callable<T> task : tasks) {
if (!(task instanceof LocalComponentTraceCallable)) {
ts.add(new LocalComponentTraceCallable<>(this.tracer, this.traceKeys,
this.spanNamer, this.spanName, task));
ts.add(new LocalComponentTraceCallable<>(tracer(), traceKeys(),
spanNamer(), this.spanName, task));
}
}
return ts;
}
Tracer tracer() {
if (this.tracer == null && this.beanFactory != null) {
this.tracer = this.beanFactory.getBean(Tracer.class);
}
return this.tracer;
}
TraceKeys traceKeys() {
if (this.traceKeys == null && this.beanFactory != null) {
this.traceKeys = this.beanFactory.getBean(TraceKeys.class);
}
return this.traceKeys;
}
SpanNamer spanNamer() {
if (this.spanNamer == null && this.beanFactory != null) {
this.spanNamer = this.beanFactory.getBean(SpanNamer.class);
}
return this.spanNamer;
}
}

View File

@@ -20,6 +20,8 @@ import java.lang.invoke.MethodHandles;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.logging.Log;
@@ -37,6 +39,7 @@ import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.instrument.async.LazyTraceExecutor;
import org.springframework.cloud.sleuth.instrument.async.TraceableExecutorService;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -70,6 +73,10 @@ public class Issue410Tests {
@Autowired Tracer tracer;
@Autowired AsyncTask asyncTask;
@Autowired RestTemplate restTemplate;
/**
* Related to issue #445
*/
@Autowired ExecutorService executorService;
@Test
public void should_pass_tracing_info_for_tasks_running_without_a_pool() {
@@ -145,6 +152,14 @@ public class Issue410Tests {
}
}
/**
* Related to issue #445
*/
@Test
public void should_wrap_executor_service_in_trace_representation() {
then(this.executorService).isInstanceOf(TraceableExecutorService.class);
}
private int port() {
return this.environment.getProperty("local.server.port", Integer.class);
}
@@ -155,11 +170,11 @@ public class Issue410Tests {
@EnableAsync
class AppConfig {
@Bean Sampler testSampler() {
@Bean public Sampler testSampler() {
return new AlwaysSampler();
}
@Bean RestTemplate restTemplate() {
@Bean public RestTemplate restTemplate() {
return new RestTemplate();
}
@@ -288,4 +303,11 @@ class Application {
return Span.idToHex(this.asyncTask.taskScheduler().getTraceId());
}
/**
* Related to issue #445
*/
@Bean public ExecutorService executorService() {
return Executors.newSingleThreadExecutor();
}
}