-
Notifications
You must be signed in to change notification settings - Fork 143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support propagating trace context to callback #287
base: master
Are you sure you want to change the base?
Support propagating trace context to callback #287
Conversation
0a7b586
to
84efc78
Compare
…submitListenable`.
84efc78
to
f082ae9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall it looks good!
Just some minor comments to clarify.
this(delegate, tracer, tracer.activeSpan()); | ||
} | ||
|
||
public TracedListenableFuture(ListenableFuture<T> delegate, Tracer tracer, Span span) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we get around only with this constructor? We could also change tracer to scope manager. It better indicates intentions that we just propagate spans.
private final Span span; | ||
|
||
public TracedListenableFutureCallback(ListenableFutureCallback<T> delegate, Tracer tracer) { | ||
this(delegate, delegate, tracer, tracer.activeSpan()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this correct? Should be the success and failure callback the same instance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's ok to put them together.
Actually, the separated version is added since spring 4.1 for optimizing lambda in java8.
And the null handling behavior follows spring-core, which is raising exceptions instantly.
/** | ||
* @author MiNG | ||
*/ | ||
public class TracedListenableFutureCallback<T> implements ListenableFutureCallback<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are all the constructors necessary? If no keep only what is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to your comment here.
I'd like to remove the overloads which has span
parameter, but the overloads of ListenableFutureCallback
and SuccessCallback
/FailureCallback
are still recommended to keep. They are useful for wrapping callbacks manually to the untraced TaskExecutors.
|
||
private final SuccessCallback<T> successDelegate; | ||
private final FailureCallback failureDelegate; | ||
private final Tracer tracer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need a tracer here? Ir might be cleaner to use the scope manager to indicate that this class only propagates the context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Em... This style follows the TracedRunnable
from https://github.com/opentracing-contrib/java-concurrent . Should we keep a same style or not?
...st/java/io/opentracing/contrib/spring/cloud/async/instrument/TracedListenableFutureTest.java
Outdated
Show resolved
Hide resolved
@JasonMing thanks for the comments. Ping me when I would re-review/merge. |
@pavolloffay I fix some CRs, and some might still need more discussions.
|
@JasonMing could you be more specific about the open questions? In your code snippet about the scope created in |
@pavolloffay here is an example (some insignificant codes are hidden) private static ListenableFuture<?> call() {
// create a sub span of 'main'
Span span = GlobalTracer.get().buildSpan("call").start();
try (Scope scope = GlobalTracer.get().activateSpan(span)) {
return TASK_EXECUTOR.submitListenable(() -> {
// the async task started in scope 'call', current activeSpan() should be 'call'
LOGGER.info("async task span: " + GlobalTracer.get().activeSpan());
// simulate blocking calls, let callback run out of main thread
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1000));
});
} finally {
span.finish();
}
}
public static void main(String[] args) {
// the root span 'main'
Span span = GlobalTracer.get().buildSpan("main").start();
try (Scope scope = GlobalTracer.get().activateSpan(span)) {
ListenableFuture<?> future = call();
// here, we add callback after 'call()' method returned, in the 'main' scope
future.addCallback(r -> {
// current activeSpan() should be 'call', not 'main'
LOGGER.info("callback span: " + GlobalTracer.get().activeSpan());
}, e -> {});
} finally {
span.finish();
}
} If we remove the span in |
Can we store the active span when It will also often happen that active span from |
Yes, that's what I do now. |
Drive-by comment, use as you wish. If you like, have a look at context-propagation-java8/ContextAwareCompletableFuture.java. Doing this correctly not as easy as it seems at first. |
Implements #286 .
The
CompletableFuture
returned byListenableFuture.completable()
is not injected yet, because there is too much methods to be processed. And the injection toCompletableFuture
should be feature of java-concurrent project. I'll open an issue forCompletableFuture
injection in java-concurrent project.