EventScheduler

Struct EventScheduler 

Source
pub struct EventScheduler { /* private fields */ }
Expand description

This scheduler will make sure that there is fairness between inputs.

The scheduler reorders events in the following way:

  • Non-input events are prioritized

    If the node received any events that are not input events, they are returned first. The intention of this reordering is that the nodes can react quickly to dataflow-related events even when their input queues are very full.

    This reordering has some side effects that might be unexpected:

    • An InputClosed event might be yielded before the last input events of that ID.

      Usually, an InputClosed event indicates that there won’t be any subsequent inputs of a certain ID. This invariant does not hold anymore for a scheduled event stream.

    • The Stop event might not be the last event of the stream anymore.

      Usually, the Stop event is the last event that is sent to a node before the event stream is closed. Because of the reordering, the stream might return more events after a Stop event.

  • Input events are grouped by ID and yielded in a least-recently used order (by ID).

    The scheduler keeps a separate queue for each input ID, where the incoming input events are placed in their chronological order. When yielding the next event, the scheduler iterates over these queues in least-recently used order. This means that the queue corresponding to the last yielded event will be checked last. The scheduler will return the oldest event from the first non-empty queue.

    The side effect of this change is that inputs events of different IDs are no longer in their chronological order. This might lead to unexpected results for input events that are caused by each other.

§Example 1

Consider the case that one input has a very high frequency and another one with a very slow frequency. The event stream will always alternate between the two inputs when each input is available. Without the scheduling, the high-frequency input would be returned much more often.

§Example 2

Again, let’s consider the case that one input has a very high frequency and the other has a very slow frequency. This time, we define a small maximum queue sizes for the low-frequency input, but a large queue size for the high-frequency one. Using the scheduler, the event stream will always alternate between high and low-frequency inputs as long as inputs of both types are available.

Without scheduling, the low-frequency input might never be yielded before it’s dropped because there is almost always an older high-frequency input available that is yielded first. Once the low-frequency input would be the next one chronologically, it might have been dropped already because the node received newer low-frequency inputs in the meantime (the queue length is small). At this point, the next-oldest input is a high-frequency input again.

§Example 3

Consider a high-frequency camera input and a low-frequency bounding box input, which is based on the latest camera image. The dataflow YAML file specifies a large queue size for the camera input and a small queue size for the bounding box input.

With scheduling, the number of buffered camera inputs might grow over time. As a result the camera inputs yielded from the stream (in oldest-first order) are not synchronized with the bounding box inputs anymore. So the node receives an up-to-date bounding box, but a considerably outdated image.

Without scheduling, the events are returned in chronological order. This time, the bounding box might be slightly outdated if the camera sent new images before the bounding box was ready. However, the time difference between the two input types is independent of the queue size this time.

(If a perfect matching bounding box is required, we recommend to forward the input image as part of the bounding box output. This way, the receiving node only needs to subscribe to one input so no mismatches can happen.)

Trait Implementations§

Source§

impl Debug for Scheduler

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FutureExt for T

Source§

fn with_context(self, otel_cx: Context) -> WithContext<Self>

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Source§

fn with_current_context(self) -> WithContext<Self>

Attaches the current Context to this type, returning a WithContext wrapper. Read more
Source§

impl<T> FutureExt for T

Source§

fn with_context(self, otel_cx: Context) -> WithContext<Self>

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Source§

fn with_current_context(self) -> WithContext<Self>

Attaches the current Context to this type, returning a WithContext wrapper. Read more
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,