-
Notifications
You must be signed in to change notification settings - Fork 344
Make Tracer extends Closable. #329
Make Tracer extends Closable. #329
Conversation
I'm +1 to this change, but haven't we had this discussion before? |
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.
This makes a lot of sense to me, and is equivalent to using the IDisposable
pattern in C#.
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 I have no problem with making Tracer Closeable, but what problem do we solve to have Tracer closeable?
Normally the one configuring the tracer in the application already knows exactly which implementation is instantiated and what its livecycle requirements are.
@@ -22,6 +22,7 @@ | |||
import io.opentracing.noop.NoopTracerFactory; | |||
import io.opentracing.propagation.Format; | |||
|
|||
import java.io.IOException; |
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.
Why the import of IOException?
I don't see it being thrown?
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.
Oh, good catch. I forgot to remove it during my cleanup.
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.
Will you remove the import before merging?
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 ;)
Hey @sjoerdtalsma So, from the mentioned RFC:
Also, there was some previous feedback (#250 (comment) and #302 (comment)) Hope that helps ;) |
@carlosalberto I have read those arguments and there seems to be a genuine need for this. Don't let my curiosity get in the way of merging by the way 😉 .. |
@sjoerdtalsma perhaps a good example is around the usage of https://github.com/opentracing-contrib/java-tracerresolver, where the user only adds it to their classpath, and does not reference their desired tracer class directly. |
I think I might have mentioned before, but one of the concrete cases where I needed this was when implementing the tracing subsystem for WildFly. Basically, the application server will create a tracer based on the tracer implementation from the application's classpath (possibly packaged inside the application's WAR) and start/close it whenever the deployment has started/finished. |
My only concern with Close() API is that it requires synchronous, uninterruptible behavior. I don't know why, but Lightstep's tracer for Go implements cancellable Close(): In Jaeger we never had requests to support that. Our Node.js implementation of Close() is asynchronous, but that's more of a side effect of Node.js style. So I am interested in hearing from existing implementations:
If yes on either question, would be good to hear & document the use cases. |
For Java, catching an IMO, having the Tracer extend Closeable has a higher value than providing a non-standard async close method, or a close method with a context (or similar). |
@yurishkuro I don't think close is cancellable in go - the context object is only used in the flush so we can ensure there's nothing in the span buffer before closing the tracer. Not really sure about the rationale for that implementation other than making it easier to close + flush in one instruction rather than two. edit - actually, now that I look at it again it does seem weird because of the return on line 180. |
I strongly agree with this. But I'm still curious on this detail, and would love so hear other points of view. |
@tylerbenson @jpkrohling Thanks for the use cases. With that I'm totally on board with this PR. I should've guessed the tracer resolver example though.. 😉 |
Apparently the rationale behind the Golang |
Hey hey @yurishkuro wondering if this makes sense to you? If you think we need more feedback, we could poke people a little bit more ;) |
* | ||
* <p> | ||
* The close method should be considered idempotent; closing an already closed Tracer should not raise an error. | ||
* Spans that are created or finished after a Tracer has been closed may or may not be flushed. |
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.
this text implies that while spans may not be flushed, the tracer must still create them like business as usual, right?
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, I'd say so (as mentioned in the spec RFC) - an alternative is to NOT allow Span objects to be created (from where? from the builder? from start
?)
* <p> | ||
* The close method should be considered idempotent; closing an already closed Tracer should not raise an error. | ||
* Spans that are created or finished after a Tracer has been closed may or may not be flushed. | ||
* Calling the close method should be considered a synchronous operation. |
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.
What should happen if tracer uses sync span export (e.g. via HTTP), is able to retry failures, and the tracing backend is down? This method theoretically can block for a long time?
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.
Oh, that's a good point. Retries are fine, I think - but that brings us to the timeout point, and whether we should tell the user it can block for long or it should return relatively soon.
Opinions on this?
(I think every Tracer should try to flush for some given time -implementation specific- and then simply give up).
I am being a bit pedantic, but the fact that Lightstep had run into this situation indicates that the use case of |
I think this is fine. We can iterate a little bit more to have better semantics ;) (worst case: if it takes too long, we can include it in a further release). I'd love to get feedback on this |
That's reasonable, but if the API was cognizant of that use case it wouldn't have to be implementation specific. I assume the option here is to return CancellableFuture, which would make the tracer not io.Closable. |
Agreed.
Also correct. But we could offer this also in the future, for 'advanced' scenarios ;) What about saying something along "this is a synchronous call, will try to flush pending Spans and shutdown related resources. Be aware of the fact it may ultimately block for long". This is perhaps too general but would help give better expectations to users. |
Is the weak guarantee, especially of freeing resources and returning, actually going to be sufficient for the people who need this functionality? |
The people that have asked for the feature, iirc, haven't mentioned anything about wanting this to be cancellable, but have mentioned try-with-resources, so I think the current evidence tips towards implementing closeable rather than cancellable. |
+1, making the Tracer implement Closeable has real benefits, such as being able to use with closeable streams and try-with-resources. Tracers aren't the only components that might depend on IO resources upon |
@jpkrohling I don't follow your point about interruption. Typically this is used when you have work done in thread A and another thread B is waiting for that work to complete (e.g. B waits on |
I expect blocking operations to not run in the main thread, so, |
Well, then to interrupt it you need another API on the tracer, and there's still nobody to actually do the interrupt because Anyway, we're getting into the weeds. My main concern is that we're saying that tracer does not need to provide any guarantee how long it will take to return from |
I understand the appeal, but I'm not aware of any standard APIs in Java for that. I'm afraid we'd be building something that deviates from what pretty much everything out there uses. If we really have a need for the feature you described, we could consider adding an overloaded method, |
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.
ok, let's do it
🎉 |
Hey all - I've removed a pair of unused imports, and added a pair of minor notes on the The plan is to merge it late Monday (start preparing the 0.32 release), btw ;) |
* <p> | ||
* For stateless tracers, this can be a no-op. | ||
*/ | ||
void close(); |
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.
Should this @Override
?
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.
Done ;)
Merged it, thank you all for the feedback! |
* Deprecate the StringTag.set() overload taking a StringTag. (#262) * Implement Trace Identifiers. (#280) * Bump JaCoCo to use a Java 10 friendly version (#306) * Remove finish span on close (#301) * Deprecate finishSpanOnClose on activation. * Add ScopeManager.activeSpan() and Tracer.activateSpan(). * Clarify the API changes and deprecations. * Add an error reporting sample to opentracing-testbed. * Simple layer on top of ByteBuffer for BINARY format. (#276) * Add generic typed setTag/withTag (#311) * Allow injecting into maps of type Map<String,Object> (#310) * Add simple registerIfAbsent to global tracer (#289) * Split Inject and Extract Builtin interfaces (#316) * Deprecate ScopeManager.active() (#326) * Make Tracer extends Closable. (#329) * Do not make isRegistered() synchronized. (#333) * Deprecate AutoFinishScopeManager (#335)
Prior to 0.32, I decided to take a shot at this feature (as part of opentracing/specification#130) - the change itself is actually minimal, and I'm guessing that this could be an easy-to-implement item for Tracer maintainers, but would definitely love some feedback.
Depending on how good or bad the changes are deemed, we might include this in the 0.32 Final Release ;)
PS - Was tempted to leave
MockTracer.close()
as no-op, but preferred to keep the invariant.@yurishkuro @tylerbenson @austinlparker @opentracing/opentracing-java-maintainers