Skip to content

migrate event handlers to one generic handler - #571

Open
jayshrivastava wants to merge 3 commits into
mainfrom
js/events
Open

migrate event handlers to one generic handler#571
jayshrivastava wants to merge 3 commits into
mainfrom
js/events

Conversation

@jayshrivastava

@jayshrivastava jayshrivastava commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

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.

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`.
@jayshrivastava jayshrivastava changed the title checkpoint migrate event handlers to one generic handler Jul 27, 2026

impl DesiredTaskCountHandler for usize {
fn handle(&self, ev: DesiredTaskCountEvent) -> Option<DesiredTaskCountEventResponse> {
impl EventHandler<DesiredTaskCountHandler> for usize {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 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 {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 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.

Comment thread src/events/common.rs
Comment on lines +14 to +18
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>;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@jayshrivastava jayshrivastava Jul 28, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well we could have two traits.
EventHandler and AsyncEventHandler

@gabotechs
gabotechs force-pushed the gabrielmusat/events branch from a4a9541 to 1871bb9 Compare July 28, 2026 09:18
Base automatically changed from gabrielmusat/events to main July 28, 2026 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants