-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
tokio-stream: add wrapper for broadcast and watch #3384
Conversation
The As for the |
That sounds like some difficult question for me to answer :) |
354649a
to
f1c0143
Compare
tokio-stream/src/wrappers/watch.rs
Outdated
pub struct WatchStream<T> { | ||
inner: Pin<Box<dyn Stream<Item = ()>>>, | ||
_marker: std::marker::PhantomData<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.
It seems like a problem to have the Stream
return ()
. The user of the Stream
would want the actual item, though I think we might have to clone it to do that?
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 thought users would mostly use this to see whether something got arrived? (Maybe I am wrong...) Or maybe it is nice to have it return the last arrived value as well.
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.
Or can I justyield rx.borrow()
? Instead of yield a ()? I am trying this and now having some difficulty to deal with the life-times.
c6bc555
to
3957c05
Compare
Signed-off-by: Fuyang Liu <[email protected]>
Signed-off-by: Fuyang Liu <[email protected]>
Co-authored-by: Alice Ryhl <[email protected]>
* add watch * Fix up
3957c05
to
34eab73
Compare
Ok((item, rx)) | ||
} | ||
|
||
impl<T: Clone + Unpin + 'static + Send + Sync> BroadcastStream<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.
With the new change, some of these bounds can be removed.
/// [`tokio::sync::broadcast::Receiver`]: struct@tokio::sync::broadcast::Receiver | ||
/// [`Stream`]: trait@crate::Stream | ||
pub struct BroadcastStream<T> { | ||
inner: ReusableBoxFuture<Result<(T, Receiver<T>), RecvError>>, |
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.
We need to return the receiver even if it emits an error, as the stream would otherwise not be usable again after returning an error.
Co-authored-by: Alice Ryhl <[email protected]>
enum WrappedRecvError<T> { | ||
Lagged(u64, Receiver<T>), | ||
Closed, | ||
} | ||
|
||
async fn make_future<T: Clone>( | ||
mut rx: Receiver<T>, | ||
) -> Result<(T, Receiver<T>), WrappedRecvError<T>> { | ||
match rx.recv().await { | ||
Ok(item) => Ok((item, rx)), | ||
Err(RecvError::Lagged(n)) => Err(WrappedRecvError::Lagged(n, rx)), | ||
Err(RecvError::Closed) => Err(WrappedRecvError::Closed), | ||
} | ||
} |
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.
We should be able to simplify to the following.
enum WrappedRecvError<T> { | |
Lagged(u64, Receiver<T>), | |
Closed, | |
} | |
async fn make_future<T: Clone>( | |
mut rx: Receiver<T>, | |
) -> Result<(T, Receiver<T>), WrappedRecvError<T>> { | |
match rx.recv().await { | |
Ok(item) => Ok((item, rx)), | |
Err(RecvError::Lagged(n)) => Err(WrappedRecvError::Lagged(n, rx)), | |
Err(RecvError::Closed) => Err(WrappedRecvError::Closed), | |
} | |
} | |
async fn make_future<T: Clone>( | |
mut rx: Receiver<T>, | |
) -> (Result<T, RecvError<T>>, Receiver<T>) { | |
let result = rx.recv().await; | |
(result, rx) | |
} |
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.
That looks much better 😄
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.
That looks much better 😄
match ready!(self.inner.poll(cx)) { | ||
Ok((item, rx)) => { | ||
self.inner.set(make_future(rx)); | ||
Poll::Ready(Some(Ok(item))) | ||
} | ||
Err(err) => match err { | ||
WrappedRecvError::Closed => Poll::Ready(None), | ||
WrappedRecvError::Lagged(n, rx) => { | ||
self.inner.set(make_future(rx)); | ||
Poll::Ready(Some(Err(BroadcastStreamRecvError::Lagged(n)))) | ||
} | ||
}, | ||
} |
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 want to call self.inner.set(make_future(rx))
in all three cases because then, if the user calls poll_next
after WrappedRecvError::Closed
, then we will just return Poll::Ready(None)
again.
With this implementation, it will panic if polled again after the first WrappedRecvError::Closed
.
You should be able to avoid duplicating the call three times by doing it before the match (but after the self.inner.poll
call).
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.
That is a good catch. Thank you 👍
match result { | ||
Ok(item) => Poll::Ready(Some(Ok(item))), | ||
Err(err) => match err { | ||
RecvError::Closed => Poll::Ready(None), | ||
RecvError::Lagged(n) => Poll::Ready(Some(Err(BroadcastStreamRecvError::Lagged(n)))), | ||
}, | ||
} |
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 could be simplified.
match result { | |
Ok(item) => Poll::Ready(Some(Ok(item))), | |
Err(err) => match err { | |
RecvError::Closed => Poll::Ready(None), | |
RecvError::Lagged(n) => Poll::Ready(Some(Err(BroadcastStreamRecvError::Lagged(n)))), | |
}, | |
} | |
match result { | |
Ok(item) => Poll::Ready(Some(Ok(item))), | |
Err(RecvError::Closed) => Poll::Ready(None), | |
Err(RecvError::Lagged(n)) => Poll::Ready(Some(Err(BroadcastStreamRecvError::Lagged(n)))), | |
} |
} | ||
} | ||
|
||
impl<T: Clone> fmt::Debug for BroadcastStream<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.
impl<T: Clone> fmt::Debug for BroadcastStream<T> { | |
impl<T> fmt::Debug for BroadcastStream<T> { |
tokio-stream/src/wrappers/watch.rs
Outdated
async fn make_future<T: Clone + Send + Sync>( | ||
mut rx: Receiver<T>, | ||
) -> Result<((), Receiver<T>), RecvError> { | ||
let signal = rx.changed().await?; | ||
Ok((signal, rx)) | ||
} |
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.
Same change here.
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.
Aha, sorry I forgot this one.
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 seems good to me now!
## Issue Addressed resolves #2129 resolves #2099 addresses some of #1712 unblocks #2076 unblocks #2153 ## Proposed Changes - Updates all the dependencies mentioned in #2129, except for web3. They haven't merged their tokio 1.0 update because they are waiting on some dependencies of their own. Since we only use web3 in tests, I think updating it in a separate issue is fine. If they are able to merge soon though, I can update in this PR. - Updates `tokio_util` to 0.6.2 and `bytes` to 1.0.1. - We haven't made a discv5 release since merging tokio 1.0 updates so I'm using a commit rather than release atm. **Edit:** I think we should merge an update of `tokio_util` to 0.6.2 into discv5 before this release because it has panic fixes in `DelayQueue` --> PR in discv5: sigp/discv5#58 ## Additional Info tokio 1.0 changes that required some changes in lighthouse: - `interval.next().await.is_some()` -> `interval.tick().await` - `sleep` future is now `!Unpin` -> tokio-rs/tokio#3028 - `try_recv` has been temporarily removed from `mpsc` -> tokio-rs/tokio#3350 - stream features have moved to `tokio-stream` and `broadcast::Receiver::into_stream()` has been temporarily removed -> `tokio-rs/tokio#2870 - I've copied over the `BroadcastStream` wrapper from this PR, but can update to use `tokio-stream` once it's merged tokio-rs/tokio#3384 Co-authored-by: realbigsean <[email protected]>
Signed-off-by: Fuyang Liu [email protected]
Motivation
Closes #3382
Solution
The basic sketch is going to be:
impl Stream
Box::pin
on that stream, the put the pinned box into the structimpl Stream on Wrapper
just forwards calls topoll_next
to the pinned box