Closed killercup closed 6 years ago
See this as a draft for an idea for a proposal to solve #11 ;)
It works, but as you can easily see, much of the code is duplicated across the targets. I have also not written a good concurrent example yet.
Commit just added:
Actually, it might be that all that effort was for nought: I've just realized we still have sync issues since out write calls are not for isolated chunks of stuff but often very many for one
We could probably do that off-thread by putting the item into a channel, but that'd require the item to implement
Send
. I'm not sure I want to do that (robustness principle and all that). I might still evaluate this in a spike branch just because I don't have enough experience to judge the effects of this.This commit surely adds a bit of tech debt, as we
Output
is now basically aVec<Arc<Mutex<Arc<InternalFormatter>>>
. Sorry.
Good enough for now. We can surely replace lots of this if a better approach appears!
Human and JSON targets now spawn a thread that will do all the stuff. This mean we now have to pass in an initializer closure so buffers don't have to be send.
Oh, and since we are dealing with threads, I've also had the pleasure of adding some channels here and there. We have one unbounded channel that takes all write requests. We keep the sender of that one, and pass the receiver to the thread. To get stuff out of the thread, we have another channel. This one is more synchronous by having a capacity of 0 -- IIRC that means it'll block until we have received its content. Of this "response channel", we pass the sender into the thread and keep a single receiver for ourselves.
While initializing the formatter, this is also the channel we block on to see if the thread started successfully or if there was an error. Because, yes, our initializer can return an error.
Along the way, I've also added a
flush
method, so that we can now in tests just call that instead of dropping the output explicitly as a sync point. (This too is synchronized using the response channel).