getUI().get().access throws and exception

Hello!
I have this pice of code that update a grid almost every second or even more. It works all the time I can see the result in the UI however I also see how it throws and exception in the console com.vaadin.flow.component.UIDetachedException

 
  @JmsListener(destination = "tick-channel", containerFactory = "jmsFactory")
  public void receiveMessage(final Tick tick) {

    this.tick = tick;

    if (getUI().isPresent()) {
      getUI().get().access(() -> {
        try {
          positionsList.forEach(p -> {
            if (p.getSecurity().getSymbol().equals(tick.getSymbol().toUpperCase())) {
              plMap.put(
                  p.getSecurity().getSymbol(),
                  formatColumnTypeNumber(positionService.calculatePL(p, tick.getClose(), BigDecimal.ZERO))
              );
            }
          });
          //TODO: fix that later not need it right now
        } catch (Exception e) {
          LOGGER.error(e);
        }
      });

      positionGrid.getDataProvider().refreshAll();
    }
  }
018-Nov-13 12:00:26 PM [DefaultMessageListenerContainer-1]
 ERROR gara.core.config.JMSConfig - Error in listener!
Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
: org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method 'public void gara.core.ui.DashboardUi.receiveMessage(gara.model.market.Tick)' threw exception; nested exception is com.vaadin.flow.component.UIDetachedException
Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:122) ~[spring-jms-5.0.9.RELEASE.jar:5.0.9.RELEASE]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:77) ~[spring-jms-5.0.9.RELEASE.jar:5.0.9.RELEASE]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:736) ~[spring-jms-5.0.9.RELEASE.jar:5.0.9.RELEASE]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:696) [spring-jms-5.0.9.RELEASE.jar:5.0.9.RELEASE]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:674) [spring-jms-5.0.9.RELEASE.jar:5.0.9.RELEASE]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:318) [spring-jms-5.0.9.RELEASE.jar:5.0.9.RELEASE]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:257) [spring-jms-5.0.9.RELEASE.jar:5.0.9.RELEASE]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1189) [spring-jms-5.0.9.RELEASE.jar:5.0.9.RELEASE]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1179) [spring-jms-5.0.9.RELEASE.jar:5.0.9.RELEASE]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1076) [spring-jms-5.0.9.RELEASE.jar:5.0.9.RELEASE]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at java.lang.Thread.run(Thread.java:748) [?:1.8.0_181]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
: Caused by: com.vaadin.flow.component.UIDetachedException
Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at com.vaadin.flow.component.UI.access(UI.java:447) ~[flow-server-1.0.5.jar:?]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at gara.core.ui.DashboardUi.receiveMessage(DashboardUi.java:231) ~[core-1.1-SNAPSHOT.jar:1.1-SNAPSHOT]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at sun.reflect.GeneratedMethodAccessor144.invoke(Unknown Source) ~[?:?]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_181]

Nov 13 12:00:26 ip-172-31-93-20 aws-Cryptonomics[5086]
:         at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_181]

Hi Ruben,

This is probably caused by a message being delivered to an UI that is not attached anymore - in other words, the user closed the tab.

One way to avoid the issue is to listen to detach events from your UI and unregister it from receiving further messages.

You can also catch the exception when calling access and unregister it there.

In newer Flow versions, you can call accessLater(SerializableRunnable accessTask, SerializableRunnable detachHandler) instead. The detachHandler callback is then executed when the UI is detached, avoiding the exception.


Gilberto

Hello Gilberto,

it is a bit strange I am trying to reproduce the error, and by closing the tab … does not appears.

About the “One way to avoid the issue is to listen to detach events from your UI and unregister it from receiving further messages.” I guess you are speaking about:

  @Override
  protected void onDetach(final DetachEvent detachEvent) {
    LOGGER.info(detachEvent);
  }

But is not so clear for me what I should “Detach”… the getUI() ? I other hand I am looking for the method accessLater, but I have only “access”, I am using the version 11.0.2 right now.

Thanks a lot for your help!

Rubén

To listen to detach events from the UI, you can use:

ui.addDetachListener(event -> {
    // ui has been detached 
});

As for the accessLater, that’s an upcoming feature of Vaadin 12. You can use the V12 beta right away, or wait for the final release on December 5th.


Gilberto

Hi Gilberto! Can you share an example of accessLater? I see it returns a SerializableRunner, who is responsible to effectively run that?