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 31e02f54e2
commit 2a740db1d2
4 changed files with 74 additions and 19 deletions

View File

@@ -598,11 +598,11 @@ a modified file in the correct place. Just commit it and push the change.
If you don't have an IDE preference we would recommend that you use
http://www.springsource.com/developer/sts[Spring Tools Suite] or
http://eclipse.org[Eclipse] when working with the code. We use the
http://eclipse.org/m2e/[m2eclipe] eclipse plugin for maven support. Other IDEs and tools
http://eclipse.org/m2e/[m2eclipse] eclipse plugin for maven support. Other IDEs and tools
should also work without issue as long as they use Maven 3.3.3 or better.
==== Importing into eclipse with m2eclipse
We recommend the http://eclipse.org/m2e/[m2eclipe] eclipse plugin when working with
We recommend the http://eclipse.org/m2e/[m2eclipse] eclipse plugin when working with
eclipse. If you don't already have m2eclipse installed it is available from the "eclipse
marketplace".

View File

@@ -17,6 +17,7 @@
package org.springframework.cloud.sleuth.instrument.async;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
@@ -43,8 +44,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

@@ -19,6 +19,8 @@ package org.springframework.cloud.sleuth.instrument.async.issues.issue410;
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;
@@ -36,6 +38,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;
@@ -67,6 +70,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() {
@@ -138,6 +145,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);
}
@@ -148,11 +163,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();
}
@@ -281,4 +296,11 @@ class Application {
return Span.idToHex(this.asyncTask.taskScheduler().getTraceId());
}
/**
* Related to issue #445
*/
@Bean public ExecutorService executorService() {
return Executors.newSingleThreadExecutor();
}
}