migrate event handlers to one generic handler - #571
Conversation
b7bbcff to
808ff47
Compare
This change migrates this pattern:
```
SessionStateBuilder::new()
.with_distributed_event_handler(desired_task_count)
.with_distributed_event_handler(scale_up_leaf_node)
.with_distributed_event_handler(route_tasks);
```
to this:
```
SessionStateBuilder::new()
.with_distributed_event_handler(desired_task_count)
.with_distributed_event_handler(scale_up_leaf_node)
.with_distributed_event_handler(route_tasks);
```
The type of handler can be inferred by the argument. Most of the
relevant change are in `src/events`.
39e8fe6 to
d114579
Compare
|
|
||
| impl DesiredTaskCountHandler for usize { | ||
| fn handle(&self, ev: DesiredTaskCountEvent) -> Option<DesiredTaskCountEventResponse> { | ||
| impl EventHandler<DesiredTaskCountHandler> for usize { |
There was a problem hiding this comment.
Any usize automatically routes to EventHandler<DesiredTaskCountHandler> which is kind of funny.
One day someone could implement impl EventHandler<MyNewKindOfHandler> for usize which means rust cannot resolve with_distributed_event_handler(2). You would have to do something like this to get it to work with_distributed_event_handler::<DesiredTaskCountHandler>(desired_task_count)
There was a problem hiding this comment.
🤔 This... does not look very good. with_distributed_event_handler(2) is too ambiguous. This implementation is only used for tests, if you ask me, I'd just remove it then.
|
|
||
| impl DesiredTaskCountHandler for usize { | ||
| fn handle(&self, ev: DesiredTaskCountEvent) -> Option<DesiredTaskCountEventResponse> { | ||
| impl EventHandler<DesiredTaskCountHandler> for usize { |
There was a problem hiding this comment.
🤔 This... does not look very good. with_distributed_event_handler(2) is too ambiguous. This implementation is only used for tests, if you ask me, I'd just remove it then.
| pub trait EventHandler<E: Event>: Send + Sync + 'static { | ||
| /// Returns `None` when this handler does not accept the event, allowing the next handler in | ||
| /// the chain to try. Returns `Some` to stop dispatch and select that response. | ||
| fn handle(&self, ev: E::Data<'_>) -> Option<E::Response>; | ||
| } |
There was a problem hiding this comment.
There's a challenge with this shape. Some other event handlers, do not need to return an Option<>, for example: https://github.com/datafusion-contrib/datafusion-distributed/pull/568/changes#diff-7bd36235787107a21e71a52b4e5511fb7c3fb66c4c6180820a6712c78022c3fe.
One thing that sounds cornering is the fact that all EventHandlers need to adhere to the same shape.
Another example is making the DesiredTaskCountHandler async:
We'd like that event hander to be async, but we want to keep the other handlers synchronous, however, I imagine here either all of them are async or none are.
There was a problem hiding this comment.
Initially, I had
fn handle(&self, ev: E::Data<'_>) -> E::Response;
but then that means each Handler needs to implement its own find_map behavior. It is nice having it here in one spot.
impl<E: Event> EventHandlerChain<E> {
pub(crate) fn handle(&self, ev: E::Data<'_>) -> Option<E::Response> {
// Give priority to custom handlers registered by users.
if let Some(res) = self
.custom
.iter()
.find_map(|handler| handler.handle(ev.clone()))
{
return Some(res);
}
// If no user handler handled the event, use the built ins.
self.builtin
.iter()
.find_map(|handler| handler.handle(ev.clone()))
}
}
The async thing is a bigger problem. Let me think about this
There was a problem hiding this comment.
Well we could have two traits.
EventHandler and AsyncEventHandler
a4a9541 to
1871bb9
Compare
This change migrates this pattern:
to this:
The type of handler can be inferred by the argument. Most of the
relevant change are in
src/events.