Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

SessionDestroyListeners are not called when an exception is thrown during detach #20293

Closed
mperktold opened this issue Oct 21, 2024 · 5 comments · Fixed by #20645
Closed

SessionDestroyListeners are not called when an exception is thrown during detach #20293

mperktold opened this issue Oct 21, 2024 · 5 comments · Fixed by #20645

Comments

@mperktold
Copy link

Description of the bug

When a VaadinSession is destroyed, first all UIs are removed and then SessionDestroyListeners are called. When removing the UIs, all the onDetach hooks and DetachListeners will be notified about it.

If one of those hooks or listeners throws an exception, the SessionDestroyListeners will not be called.

Expected behavior

Exceptions in detach hooks and listeners should not prevent SessionDestroyListeners from being called.

Minimal reproducible example

public class SessionDestroyIssue extends VerticalLayout {

    public SessionDestroyIssue() {
        var vaadinSession = VaadinSession.getCurrent();
        vaadinSession.getService().addSessionDestroyListener(e -> System.out.println("Session destroyed"));
        var closeSession = new Button("close session", e -> vaadinSession.close());
        var badDiv = new Div();
        badDiv.addDetachListener(e -> {
            throw new IllegalStateException("test");
        });
        add(closeSession, badDiv);
    }
}

Versions

  • Vaadin / Flow version: 24.4.13
  • Java version: Temurin 21.0.5+11
  • OS version: Windows 11
@mshabarov
Copy link
Contributor

mshabarov commented Oct 22, 2024

Suppose Vaadin catches the exceptions when invoking detach listeners, how then it should handle this exception? Moreover, how should it tell session destroy listeners invoker to ignore this exception?
Also, what happens if other listeners (else than detach listeners) throw an exception?
I don't want to make this catch in framework and think it's better to handle/process an exception right away in the listener rather than rely on the framework.

@mperktold
Copy link
Author

I agree that in general, we should just let the exception bubble up and not pretend that everything is fine. But I would rather apply that to the detach hooks, as they do not know whether they are invoked because the session is destroyed, or a component is removed from the dom, or maybe even just reattached.

Vaadin offers an API to get notified when the session is destroyed. When I use that API, I expect that to work reliably, without having to check every detach hook of my application, including third party tools. It should be the responsibility of the destroy event mechanism to guarantee that listeners are properly called, not the responsibility of every detach hook.

Now regarding what to do exactly and how to handle it, I think we should look at what VaadinService.fireSessionDestroy does now. It already catches exceptions thrown by the destroy listeners themselves to make sure all the listeners are called, even if one of them throws. The exception is handled by simply passing it to the session error handler:

List<UI> uis = new ArrayList<>(session.getUIs());
for (final UI ui : uis) {
ui.accessSynchronously(() -> {
/*
* close() called here for consistency so that it is always
* called before a UI is removed. UI.isClosing() is thus
* always true in UI.detach() and associated detach
* listeners.
*/
if (!ui.isClosing()) {
ui.close();
}
session.removeUI(ui);
});
}
SessionDestroyEvent event = new SessionDestroyEvent(
VaadinService.this, session);
Stream.concat(session.destroyListeners.stream(),
sessionDestroyListeners.stream()).forEach(listener -> {
try {
listener.sessionDestroy(event);
} catch (Exception e) {
/*
* for now, use the session error handler; in the
* future, could have an API for using some other
* handler for session init and destroy listeners
*/
session.getErrorHandler().error(new ErrorEvent(e));
}
});

I think something similar would work also in the loop before where all the UIs are removed. For the sake of this issue, one big try catch around the whole loop would be enough, but in the same spirit I would say that failing to remove one UI should not prevent the next UI to be removed, so probably a try-catch for each UI would be best.

@mshabarov mshabarov self-assigned this Nov 12, 2024
@mshabarov mshabarov moved this from 🆕 Needs triage to 🔎 Investigation in Vaadin Flow bugs & maintenance (Vaadin 10+) Dec 3, 2024
@mshabarov mshabarov removed their assignment Dec 3, 2024
@mshabarov mshabarov moved this from 🟢Ready to Go to 🪵Product backlog in Vaadin Flow ongoing work (Vaadin 10+) Dec 3, 2024
@mshabarov mshabarov moved this from 🔎 Investigation to 🔖 High Priority (P1) in Vaadin Flow bugs & maintenance (Vaadin 10+) Dec 4, 2024
@mshabarov mshabarov moved this from 🪵Product backlog to 🟢Ready to Go in Vaadin Flow ongoing work (Vaadin 10+) Dec 4, 2024
@tepi tepi self-assigned this Dec 5, 2024
@tepi tepi moved this from 🟢Ready to Go to ⚒️ In progress in Vaadin Flow ongoing work (Vaadin 10+) Dec 5, 2024
@github-project-automation github-project-automation bot moved this from ⚒️ In progress to Done in Vaadin Flow ongoing work (Vaadin 10+) Dec 9, 2024
@github-project-automation github-project-automation bot moved this from 🔖 High Priority (P1) to ✅ Closed in Vaadin Flow bugs & maintenance (Vaadin 10+) Dec 9, 2024
vaadin-bot pushed a commit that referenced this issue Dec 9, 2024
When session destroy is triggered,
wraps each UI close/detach to
catch exceptions, making sure
session destroy listeners are called.

Fixes #20293
vaadin-bot pushed a commit that referenced this issue Dec 9, 2024
When session destroy is triggered,
wraps each UI close/detach to
catch exceptions, making sure
session destroy listeners are called.

Fixes #20293
vaadin-bot pushed a commit that referenced this issue Dec 9, 2024
When session destroy is triggered,
wraps each UI close/detach to
catch exceptions, making sure
session destroy listeners are called.

Fixes #20293
tepi added a commit that referenced this issue Dec 9, 2024
When session destroy is triggered,
wraps each UI close/detach to
catch exceptions, making sure
session destroy listeners are called.

Fixes #20293

Co-authored-by: Teppo Kurki <teppo.kurki@vaadin.com>
tepi added a commit that referenced this issue Dec 9, 2024
When session destroy is triggered,
wraps each UI close/detach to
catch exceptions, making sure
session destroy listeners are called.

Fixes #20293

Co-authored-by: Teppo Kurki <teppo.kurki@vaadin.com>
tepi added a commit that referenced this issue Dec 9, 2024
When session destroy is triggered,
wraps each UI close/detach to
catch exceptions, making sure
session destroy listeners are called.

Fixes #20293

Co-authored-by: Teppo Kurki <teppo.kurki@vaadin.com>
@vaadin-bot
Copy link
Collaborator

This ticket/PR has been released with Vaadin 24.6.0.rc1 and is also targeting the upcoming stable 24.6.0 version.

@vaadin-bot
Copy link
Collaborator

This ticket/PR has been released with Vaadin 24.4.21.

@vaadin-bot
Copy link
Collaborator

This ticket/PR has been released with Vaadin 24.5.9.

# for free to join this conversation on GitHub. Already have an account? # to comment