-
Notifications
You must be signed in to change notification settings - Fork 324
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
Wrap Runnable in AsyncContext.start #388
Wrap Runnable in AsyncContext.start #388
Conversation
@Nullable | ||
private Runnable delegate; | ||
@Nullable | ||
private Transaction transaction; |
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 this be changed to AbstractSpan
?
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.
Good point- it can and should for other usages
Codecov Report
@@ Coverage Diff @@
## master #388 +/- ##
============================================
- Coverage 71.97% 71.46% -0.52%
+ Complexity 1203 1199 -4
============================================
Files 132 133 +1
Lines 4564 4612 +48
Branches 468 471 +3
============================================
+ Hits 3285 3296 +11
- Misses 1066 1103 +37
Partials 213 213
Continue to review full report at Codecov.
|
|
||
@Override | ||
public void run() { | ||
Scope scope = null; |
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.
I think this can be simplified to
if (transaction != null) {
transaction.activate();
try {
delegate.run();
} catch (Exception e) {
transaction.captureException(e);
throw e;
} finally {
transaction.deactivate();
}
}
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.
Well, I don't want to give up the try/catch around activate
/deactivate
- it's just like your other PR to catch errors during advices - our code should never prevent user code from running. I can give up the usage of scope though.
Your suggestion to capture the Exception and report as error is tempting, but is not safe here. Notice that this code is not taking responsibility on ending and reporting the Transaction, it's just responsible for scoping in that thread. For example, the usage of AsyncContext.onComplete
would end the transaction in this PR (and AsyncContext.onError
will report errors). So I don't know what the status of the transaction is at this stage.
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.
Good point on the problems with captureException
. However, AbstractSpan#activate
already catches exceptions.
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 it valid to deactivate a finished span? Ideally, #end
should be the last call on a span because after that the span is recycled and could be reused any time. Deactivating after that is borderline but probably unproblematic if the state isn't changed after #end
.
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.
Although it seems weird, I think it is completely valid and safe. deactivate
does two things:
- removes from the current threads stack
- invokes registered
SpanListener.onDeactivate
(which currently only implemented for MDC)
Both of these are only doing un-registration on a thread context level, so even if the span has been recycled and reused and even if it is active on a different thread, all this call is doing is making it non-active in regard to this specific thread (there is nothing preventing a span object from being active on two threads concurrently).
We just need to make sure future SpanListener
implementations are maintaining this behavior. Maybe it's best if we add to the SpanListener
interface documentation that it should only deal with registering/unregistering span on thread context, but should never assume anything about span state.
e89c0c4
to
159f368
Compare
if (tracer != null) { | ||
final Transaction transaction = tracer.currentTransaction(); | ||
if (transaction != null && runnable != null && asyncHelper != null) { | ||
runnable = asyncHelper.getForClassLoaderOfClass(AsyncContext.class).wrapRunnable(runnable, transaction); |
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.
wouldn't it be easier to just call the wrapRunnable
method on the tracer
instance? Then you could also remove the wrapRunnable
from the helper.
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.
When implementing I imagined it will do some additional stuff, but probably no need for that as it is now
@Nullable | ||
private AbstractSpan<?> span; | ||
@Nullable | ||
private ElasticApmTracer 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.
make final and remove @Nullable
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.
Hmm, didn't realize we don't recycle this reference...
Will do
if (span != null) { | ||
span.deactivate(); | ||
} | ||
//noinspection ConstantConditions |
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 be removed when making tracer nonnull
} | ||
|
||
try { | ||
//noinspection ConstantConditions |
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.
it's safer to add a null check than to suppress these inspections
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.
I know it's not null. I don't like to add null checks just to satisfy inspections... There are already too many non-required null checks.
this.tracer = tracer; | ||
} | ||
|
||
public InScopeRunnableWrapper wrap(Runnable delegate) { |
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.
Maybe add AbstractSpan
as a second parameter and remove the withScope
method? Calling one without the other would lead to an invalid state anyway.
4457d4e
to
ae72743
Compare
No description provided.