-
Notifications
You must be signed in to change notification settings - Fork 3
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
Allow components that will check their status asynchronously #7
Conversation
… normal component, but retrieve and store the result on a different thread.
…ntroduce thin wrapping of Semaphore for test readability.
…ate hook throws an exception.
…ng async components.
Allow components that will check their status asynchronously
Hi @Grundlefleck, I understand what you are trying to achieve with this change, and it was something that @tomwhoiscontrary and I discussed several times. I'm not convinced, however, that this implementation is ideal. I'm concerned that each component is coupled to the execution framework, and would personally have sought to implement by composing an asynchronous component from a normal component. I think it would be desirable set up a status page generator that takes ownership of the executor, and not give knowledge of this to the components. Do you have any thoughts on this? |
"implement by composing an asynchronous component from a normal component" - isn't that what this does? Granted, it also has the overarching AsyncStatusPageGenerator thingy, but you could use the async components without it. Hence, i would look for a way to do without the async generator altogether; it looks like it's principally a way to coordinate starting and stopping a bunch of async components, and that feels like a concern which should be separate from aggregating their outputs. Bit dubious about accessing two separate atomics. Racy. Would prefer a single atomic holding a composite object, or just good old fashioned synchronized blocks - as long as the only actions inside the blocks on either side of the wall are a pair of stores and a pair of loads, there's no troubling concurrency bottleneck. Also a bit dubious about the proliferation of single-thread scheduled executors. My gut feeling is that you want to find a way to safely manage N possibly-slow components from a single pool of M threads, where in happy times M << N. Something like a CachedThreadPoolExecutor driving the components via a facade which stops any component which is still running from being called again. 65% chance this is already in java.util.concurrent, 80% chance it's in Guava. Anyway, REJECT, one source file has no newline at end of file, unacceptable. Suggest getting J-Fred to sponsor a hackathon next time you're down south, @Grundlefleck, we can apply finishing @scarytom - appeasing touches then. |
Thanks for comments. This is a first cut that got us where we needed to be, and didn't change anyone else's usage, happy to tweak it until we're all happy.
Just so we're on the same page, do you mean the Java Executor Framework (
That is what the current implementation is designed to do. Users should now be able to write their components as-if-single-threaded, with
Some background on why it looks as it does. We wanted to achieve two things:
Consider a badly written component that fails to time out when making a network call: if threads from an underlying executor get used up as they're all waiting on this call, other components will become stale, and will change to a WARNING. The warning can be a false positive, because there's no real issue with what the component is checking. My interest is that we can achieve those two things, but I don't feel particularly strongly that the implementation has to remain the way it is. Having said that, knowledge of the executor does not get leaked to the user-created components, only the To summarise: I think the current design what you are suggesting. If there's a mismatch, could you explain in a bit more detail? |
It is...
... and it probably should be. The only bits of it that are about aggregating outputs just delegate to the preexisting
Agreed. Will fix. Probably with the composite object approach you suggested.
Worth bearing in mind that the point of this construct is to protect against slow running component checks, most likely involving network calls. Writes will likely be infrequent, with many more (fast) reads in the meantime. Given that, I wasn't particularly concerned about the performance at the level of volatile writes and reads. Let me know if you think that's negligent.
Could you be more specific about what your concern is? Creating too many under-utilized threads? Unfriendly API?
Given the concern I mentioned in an earlier comment, to guarantee a misbehaving component does not cause failures in other, unrelated components, I don't immediately see a way to achieve that with # threads < # components. Suggestions welcome.
I will LITERALLY never forgive myself. |
Just realised that this pull request (even with pending rework) could satisfy issue #3. |
FYI just had a good chat with @jheister about some changes, which match pretty closely with @tomwhoiscontrary's points, so don't waste too much time thinking about it until you see the result of those changes, which I'm about to start work on. |
It's preferable to serve a status page quickly. If the status of components are generated synchronously, during a request, it can cause the entire request to hang or be expensive. This pull request allows wrapping normal, written-as-synchronous components to be wrapped in an
AsyncComponent
, that will check the status periodically, and serve the current status very quickly.Features of
AsyncComponent
:Executor
Executor
per component, to prevent backups of one component causing other components to hangExample usage (shown with defaults):
(equivalent to):
This should then be given to an instance of
AsyncStatusPageGenerator
, similar to before:The instance of
AsyncStatusPageGenerator
can then be given whereverStatusPageGenerator
was previously given.