Reimplement watcher backoff as FSM - #720
Conversation
| //}) | ||
| ws | ||
| let next_item = this.stream.try_poll_next(cx); | ||
| if let Poll::Ready(Some(Err(_))) = &next_item { |
There was a problem hiding this comment.
This still bubbles up the error, because otherwise the user has no way of logging what's going on. The "actual" indicator for a fatal error is that the Stream closes (returns None).
There was a problem hiding this comment.
oh, right, so the it's still technically a TryStream, but the user can just drop the errors. That seems reasonable to me.
c202c95 to
adc7c43
Compare
Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se>
Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se>
Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se>
Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se>
Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se>
adc7c43 to
830204b
Compare
Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se>
Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se>
Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se>
clux
left a comment
There was a problem hiding this comment.
You are a lifesaver. Thank you so much.
| match this.state.as_mut().project() { | ||
| StreamBackoffStateProj::BackingOff(mut backoff_sleep) => match backoff_sleep.as_mut().poll(cx) { | ||
| Poll::Ready(()) => { | ||
| tracing::debug!(deadline = ?backoff_sleep.deadline(), "Backoff complete, waking up"); | ||
| this.state.set(State::Awake) | ||
| } | ||
| Poll::Pending => { | ||
| let deadline = backoff_sleep.deadline(); | ||
| tracing::trace!( | ||
| ?deadline, | ||
| remaining_duration = ?deadline.saturating_duration_since(Instant::now()), | ||
| "Still waiting for backoff sleep to complete" | ||
| ); | ||
| return Poll::Pending; | ||
| } | ||
| }, | ||
| StreamBackoffStateProj::GivenUp => { | ||
| tracing::debug!("Backoff has given up, stream is closed"); | ||
| return Poll::Ready(None); | ||
| } | ||
| StreamBackoffStateProj::Awake => {} | ||
| } |
There was a problem hiding this comment.
This is great. Really appreciate the work here. I felt super stuck and frustrated last night, and it would not have occurred to me to try to do a manual Stream impl with this before the poll delegation.
| assert_eq!(poll!(rx.next()), Poll::Pending); | ||
| tokio::time::advance(Duration::from_secs(3)).await; | ||
| assert_eq!(poll!(rx.next()), Poll::Pending); | ||
| tx.unbounded_send(Err(3)).unwrap(); | ||
| assert_eq!(poll!(rx.next()), Poll::Ready(Some(Err(3)))); | ||
| tx.unbounded_send(Ok(4)).unwrap(); | ||
| assert_eq!(poll!(rx.next()), Poll::Pending); | ||
| tokio::time::advance(Duration::from_secs(3)).await; | ||
| assert_eq!(poll!(rx.next()), Poll::Pending); | ||
| tokio::time::advance(Duration::from_secs(2)).await; | ||
| assert_eq!(poll!(rx.next()), Poll::Ready(Some(Ok(4)))); | ||
| assert_eq!(poll!(rx.next()), Poll::Pending); |
There was a problem hiding this comment.
Maybe add a // pending because stream empty or // pending because backing off N seconds
on the assert_eq!(poll!(rx.next()), Poll::Pending); lines for readability.
| let rx = stream::iter([Ok(0), Ok(1), Err(2), Ok(3), Ok(4)]); | ||
| let rx = StreamBackoff::new(rx, backoff::backoff::Constant::new(tick)); | ||
| pin_mut!(rx); | ||
| assert_eq!(poll!(rx.next()), Poll::Ready(Some(Ok(0)))); | ||
| assert_eq!(poll!(rx.next()), Poll::Ready(Some(Ok(1)))); | ||
| assert_eq!(poll!(rx.next()), Poll::Ready(Some(Err(2)))); | ||
| assert_eq!(poll!(rx.next()), Poll::Pending); | ||
| tokio::time::advance(tick * 2).await; | ||
| assert_eq!(poll!(rx.next()), Poll::Ready(Some(Ok(3)))); | ||
| assert_eq!(poll!(rx.next()), Poll::Ready(Some(Ok(4)))); | ||
| assert_eq!(poll!(rx.next()), Poll::Ready(None)); |
Based on kube-rs/kube#720, but with generalizations for runtime-agnosticity, and and pin-project-lite.
* implement backoff for watcher - for #577 Signed-off-by: clux <sszynrae@gmail.com> * move magic number into strategy Signed-off-by: clux <sszynrae@gmail.com> * expose backoff from watcher and semi-propagate into controller awkward. will write a comment Signed-off-by: clux <sszynrae@gmail.com> * potential abstraction Signed-off-by: clux <sszynrae@gmail.com> * another builder layer; allow eliding ListParams Signed-off-by: clux <sszynrae@gmail.com> * forgot to add file Signed-off-by: clux <sszynrae@gmail.com> * easy parts of code review Signed-off-by: clux <sszynrae@gmail.com> * rewrite as a helper (take N) jesus this stuff is hard. Signed-off-by: clux <sszynrae@gmail.com> * rename as suggested Signed-off-by: clux <sszynrae@gmail.com> * Reimplement watcher backoff as FSM (#720) * Fix clippy warnings Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Reimplement watch backoff as FSM Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Remove useless lifetime bounds Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Silence clippy size warning Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Silence clippy properly this time around Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Split StreamBackoff into a separate utils module Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Backoff tests Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Add stream close test Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * remove backoff pin, fix docs Signed-off-by: clux <sszynrae@gmail.com> * newline Signed-off-by: clux <sszynrae@gmail.com> * Add `Backoff` wrapper that implements client-go's reset timer behaviour (#729) Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * use new reset backoff and replicate client-go reflector values Signed-off-by: clux <sszynrae@gmail.com> * fix node watcher example Signed-off-by: clux <sszynrae@gmail.com> * Use released `backoff` Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Factor out default `Backoff` Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Add note to `watcher` about backoff Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Added backoff to Controller Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Changelog Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Revert `Observer` for now Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * The clippyman comes for us all, eventually And we must all pay our due respects, or pay the price. Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * Fix build warnings Signed-off-by: Teo Klestrup Röijezon <teo@nullable.se> * remove backoff_watch Signed-off-by: clux <sszynrae@gmail.com> * doc tweaks Signed-off-by: clux <sszynrae@gmail.com> * sentence Signed-off-by: clux <sszynrae@gmail.com> * upgrading backoff is not actually breaking Signed-off-by: clux <sszynrae@gmail.com> Co-authored-by: Teo Klestrup Röijezon <teo.roijezon@stackable.de> Co-authored-by: Teo Klestrup Röijezon <teo@nullable.se>
Part of #703