tonarino / actor

A minimalist actor framework aiming for high performance and simplicity.
MIT License
40 stars 6 forks source link

Add new "skipped" message priority #81

Open facetious opened 4 months ago

facetious commented 4 months ago

Sometimes we want to outright reject messages without processing them. It would be nice to be able to block them from even entering a queue. For example:

pub enum Priority {
    Normal,
    High,
    PolitelyRefused,
}

This could allow:

enum Treat {
  Apple,
  Banana,
  Cookie,
}

struct Child;
impl Actor for Child {
  type Message = Treat;
  fn priority(message: &Self::Message) -> Priority {
    match message {
      Treat::Apple => Priority::High,
      Treat::Banana => Priority::Normal,
      Treat::Cookie => Priority::PolitelyRefused,
    }
  }
}

where Treat::Cookie no longer impacts either queue size of Child. Because the priority selection is already a filter, allowing a 'skip' filter here feels like the best fit, rather than filtering within handle. This is especially useful when a particular shape is noisy but unwanted: in the example, if there are 20x more Treat::Cookie, our queue size requirements would be impacted, even though the messages would be ultimately skipped.

Naming is up to you; I'm not married to PolitelyRefused. Alternates: Skip, Reject, Pass, None.

In the same vein, changing the trait requirement from Into<E> to TryInto<E> would go a long way to help publish, too.

strohel commented 4 months ago

Thanks for the request, @facetious, and sorry for a delay responding.

It feels to me that a Priority like PolitelyRefused doesn't fit in the current design, but I have 2 options to likely achieve the behavior you desire:

  1. (more straightforward). Implement this on the sending side yourself. You can wrap tonari_actor::Addr<A: Actor> in yourcrate::FilteringAddr<A: FilteringActor>, where FilteringActor trait implements Actor plus some accepts_message(&M) method. Alternatively this could be implemented on the Recipient level (FilteringRecipient) if the knowledge of the message is enough (i.e. if you don't need to know the particular actor).

  2. Make the priorities defined by the actors themselves. I was never too keen on hardcoding a set of priorities for all actors, better if each one can define their own. This may be rather hart to implement - i.e. stretching the Rust type system.