vaadin / multiplatform-runtime

4 stars 1 forks source link

Async request breaks Vaadin 14 MPR UI #86

Closed caalador closed 3 years ago

caalador commented 3 years ago

Copy from issue made by @TobseF

Problem

We are migrating our monolithic business app with the MPR to Vaadin 14.4.8. But in the current state our app is very unstable and often breaks with a "frozen UI". The page loads all content, but it never stops showing the loading indicator and shows a JS Error message.

⚠ JS Client Error

$0.firstElementChild.setResponse is not a function
2021-05-20_12h42_17

After that exception, the waring Gave up waiting for message seems to indicate, that the client-server communication is broken.

⚠ JS Client Warning

com.vaadin.addons.widgetsets.AddonWidgetset-0.js:10797 
Thu May 20 12:51:09 GMT+200 2021 com.vaadin.client.communication.MessageHandler
WARNING: Gave up waiting for message 1 from the server

It seems, that it happens when an async UI Runnable (getUI().access(...)) get's executed before the initial framework request is finished. Then the client is not ready to service this request. Push in enabled by the @Push annoation.

Here you can see the Request order in such a case in recorded Browser session:

2021-05-20_12h54_52

This behavior is new with the MPR and happens when the UI is loaded. We can reproduce it several times with a Selenium Test. It happens in 2 of 4 runs. It happen even every time if we set throttle the browser in debug settings to network Fast-3G.

Expected Behavior

No matter when we call ui.access(...) the client should only get updates, after it's loaded and ready to serve push requests. Push updates should never destroy the client ui in such a way, that loading-indicator and user page interaction breaks.

Versions:

⚡Full stacktrace

client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1017 Exception is thrown during JavaScript execution. Stacktrace will be dumped separately.
cu @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1017
bu @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:973
_t @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:583
Hr @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:497
es @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1027
AB @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:942
Jr @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1022
$r @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1027
qk @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:428
Br @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1023
Cr @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1003
Bp @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1027
(anonymous) @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:993
sb @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:436
vb @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:888
(anonymous) @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:623
_f @ vaadinPush.js?v=2.4.6:2765
_invokeFunction @ vaadinPush.js?v=2.4.6:2754
_invokeCallback @ vaadinPush.js?v=2.4.6:2884
_websocket.onmessage @ vaadinPush.js?v=2.4.6:1457
client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:212 (TypeError) : $0.firstElementChild.setResponse is not a function
ZC @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:212
Xn @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1005
Wn @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:771
Yn @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:598
cu @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1017
bu @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:973
_t @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:583
Hr @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:497
es @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1027
AB @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:942
Jr @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1022
$r @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1027
qk @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:428
Br @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1023
Cr @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1003
Bp @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1027
(anonymous) @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:993
sb @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:436
vb @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:888
(anonymous) @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:623
_f @ vaadinPush.js?v=2.4.6:2765
_invokeFunction @ vaadinPush.js?v=2.4.6:2754
_invokeCallback @ vaadinPush.js?v=2.4.6:2884
_websocket.onmessage @ vaadinPush.js?v=2.4.6:1457
client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:199 The error has occurred in the JS code: '$0, $1, $0.firstElementChild.setResponse($1)'
_C @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:199
cu @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1017
bu @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:973
_t @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:583
Hr @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:497
es @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1027
AB @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:942
Jr @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1022
$r @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1027
qk @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:428
Br @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1023
Cr @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1003
Bp @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:1027
(anonymous) @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:993
sb @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:436
vb @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:888
(anonymous) @ client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:623
_f @ vaadinPush.js?v=2.4.6:2765
_invokeFunction @ vaadinPush.js?v=2.4.6:2754
_invokeCallback @ vaadinPush.js?v=2.4.6:2884
_websocket.onmessage @ vaadinPush.js?v=2.4.6:1457
client-5C40CA4B9D1F93A241DF9189632E0919.cache.js:200  Processing time was 5ms
pleku commented 3 years ago

Since there is no exact code to reproduce the issue, I need to ask some clarifying questions:

It seems, that it happens when an async UI Runnable (getUI().access(...)) get's executed before the initial framework request is finished

a) Do you mean that this only happens for the initial page render ? For example when refreshing the page ?

b) Is the UI object instance where the access callback is being invoked of type class MprUI or UI ? Based on the JS exception it should be MprUI but just to be sure

ToScope commented 3 years ago

a) Our test starts with a very simple Vaadin Flow page (in the same app, SampleUI), before it switches to our main application where this error happens. So it's not the initial render of the browser, but the seconds main-app page uses another UI (FrontendUI). By switching to the different UI, the browser reloads many files.

b) Both, SampleUI and FrontendUIextend theMprUI`.

pleku commented 3 years ago

a) Our test starts with a very simple Vaadin Flow page (in the same app, SampleUI), before it switches to our main application where this error happens. So it's not the initial render of the browser, but the seconds main-app page uses another UI (FrontendUI). By switching to the different UI, the browser reloads many files.

Ok now I would be even more interested in getting the code to reproduce this to safe time. How is the switching happening between the two UIs ? Is there some redirect ? How is that done ?

And I need to ask that what is the purpose of switching between the UIs ? Why would you not have just one UI and then switch the shown Flow routes instead that encapsulate the legacy parts inside it ? I don't think it is mentioned anywhere that you should be able to use multiple UIs with Flow even with MPR in place, so would need to understand better that what you are trying to achieve and why. Thanks

TobseF commented 3 years ago

For now, we don't have a minimal example to demonstrate the problem. As you mentioned, it's not clear if using multiple UIs in the same app is working. From the Vaadin support, I got answers from... "RTFM this is not supported", to "yes, in your setup this should work". The MPR migration guide says "Multiple UIs are not supported".

The important question, of why we have this multiple UI setup. In our BIG monolithic application, we have different sections which use independent styling. The idea when this design decision was made was: Don't deliver the whole CSS of the platform or even the admin section, if the user just opens the login page. We also have pages which are accessible without a login - we call them guest sites. Also, here we wanted to hide internal CSS which is not needed. And for development, we also deliver a sampler with our components (like the new design systems) application, which has its own styling. In addition to this CSS optimization, we put much logic of these different sections into the individual UI classes. A lot of that is already refactored during the MPR migration, but completely removing these UI-classes would be another task.
To be concrete, In our application we have 11 different UI-classes. If possible, we want to avoid merging them together during the mpr migration.

Here you can see how we set up two of these independent sections - we call them application.

AppApplication.java

@Route(value = "app")
@MprTheme(ThemeVariant.ThemeName.FRONTEND)
@LegacyUI(FrontendUI.class)
@MprWidgetset("com.vaadin.addons.widgetsets.AddonWidgetset")
@Push
public class AppApplication extends Div  {

LoginApplication .java

@Route(value = "login")
@MprTheme(ThemeVariant.ThemeName.LOGIN)
@LegacyUI(LoginUI.class)
@Push
@MprWidgetset("com.vaadin.addons.widgetsets.AddonWidgetset")
public class LoginApplication extends MprNavigatorRoute , HasDynamicTitle {

Changing the application from Login to App is done with

getPage().open("app","_blank")

This works as expected without our freezing problem. The case which crashes the UI is when our Selenium switches from a simple SamplerApplication page to the AppApplication by chaining the URL in the browser. But for us, it seems that not switching the UI is the problem. It seems to be a general problem when loading the UI takes longer (e.g. wen we throttle the browser) and an async getUI().access(...) sends data to the client which is not ready.

pleku commented 3 years ago

Don't deliver the whole CSS of the platform or even the admin section, if the user just opens the login page. To be concrete, In our application we have 11 different UI-classes. If possible, we want to avoid merging them together during the mpr migration.

I understand that you will be keeping this CSS as "v8 code", because for newer v14+ parts it is not even possible. Unless you customize the frontend build process somehow or dynamically inject the CSS/stylesheet that should be loaded, you will end up into a situation where all the CSS will be loaded regardless of what UI the user opens. I have not heard of a situation before with v14+ where there would be so much CSS to be loaded that it is a problem if all of it is loaded. So I'm not sure if the optimization is worth the trouble in the end.

Secondly, using this type of "unorthodox" setup might lead into further problems later on. I would simply recommend working your code from using UIs to @Route and/or RouterLayouts (and PageConfigurator if needed) that utilize the routing instead when moving between different parts.

Changing the application from Login to App is done with getPage().open("app","_blank")

But this opens the new UI in another new window/tab and leaves the old UI open in the browser. So this is not really switching but opening another UI. Switching would be done with getPage().setLocation("app"); instead. And you could close the existing UI so that it and all the components don't stay in the memory server side.

This works as expected without our freezing problem. The case which crashes the UI is when our Selenium switches from a simple SamplerApplication page to the AppApplication by chaining the URL in the browser. But for us, it seems that not switching the UI is the problem. It seems to be a general problem when loading the UI takes longer (e.g. wen we throttle the browser) and an async getUI().access(...) sends data to the client which is not ready.

So I assume the selenium code does another getDriver().open("app"); call in the middle of the test ? And then there is some asynchronous push-call done after some time which breaks on the client side. Based on this, it should be enough to create a simple MPR app with a TB test that fails even for just one UI. So basically it opens a UI, then the test opens it again with maybe some parameter ?push given that will trigger the asynchronous call this time and make things fail. I would expect the Vaadin support should be able to help you get this reproduced or do it for you. Or help you with the other alternatives on the table.

TobseF commented 3 years ago

In the meantime I was able to get the JS stack trace. Therefore I upgraded our setup to Vaadin 14 version: 14.6.0 and Vaadin Flow Plugin version: 2.6.0. This was needed, because of missing jfrog dependencies, which prevent to build flow 2.4.

In the flow project I set:

<gwt.module.style>PRETTY</gwt.module.style>

After building I included the client lib. Also had to exclude it on several places to make sure only the SNAPSHOT version is available.

<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>flow-client</artifactId>
    <version>2.6-SNAPSHOT</version>
</dependency>

⚡ Browser Stack Traces

I hope it will help to nail that problem.

client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:1893 Uncaught TypeError: $0.firstElementChild.setResponse is not a function
    at Object.eval (eval at $invoke (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6387), <anonymous>:3:22)
    at $invoke (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6388)
    at $handleInvocation (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6377)
    at $execute (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6315)
    at $lambda$4 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5347)
    at MessageHandler$lambda$4$Type.flush_5 [as flush] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5601)
    at flush_17 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:9762)
    at $processMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5391)
    at MessageHandler$lambda$0$Type.execute_12 [as execute_0] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5568)
    at runWhenEagerDependenciesLoaded (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:2331)
    at $handleJSON (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5277)
    at $handlePendingMessages (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5312)
    at $resumeResponseHandling (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5449)
    at $processMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5426)
    at MessageHandler$lambda$0$Type.execute_12 [as execute_0] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5568)
    at runWhenEagerDependenciesLoaded (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:2331)
    at $handleJSON (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5277)
    at $handleMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5294)
    at XhrConnection$XhrResponseHandler.onSuccess_1 [as onSuccess] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6236)
    at Xhr$Handler.onReadyStateChange (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:10084)
    at XMLHttpRequest.<anonymous> (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:1582)
    at apply_0 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:915)
    at entry0 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:954)
    at XMLHttpRequest.<anonymous> (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:942)
client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:1893 Uncaught TypeError: $0.firstElementChild.setResponse is not a function
    at Object.eval (eval at $invoke (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6387), <anonymous>:3:22)
    at $invoke (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6388)
    at $handleInvocation (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6377)
    at $execute (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6315)
    at $lambda$4 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5347)
    at MessageHandler$lambda$4$Type.flush_5 [as flush] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5601)
    at flush_17 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:9762)
    at $processMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5391)
    at MessageHandler$lambda$0$Type.execute_12 [as execute_0] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5568)
    at runWhenEagerDependenciesLoaded (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:2331)
    at $handleJSON (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5277)
    at $handlePendingMessages (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5312)
    at $resumeResponseHandling (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5449)
    at $processMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5426)
    at MessageHandler$lambda$0$Type.execute_12 [as execute_0] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5568)
    at runWhenEagerDependenciesLoaded (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:2331)
    at $handleJSON (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5277)
    at $handlePendingMessages (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5312)
    at $resumeResponseHandling (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5449)
    at $processMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5426)
    at MessageHandler$lambda$0$Type.execute_12 [as execute_0] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5568)
    at runWhenEagerDependenciesLoaded (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:2331)
    at $handleJSON (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5277)
    at $handleMessage (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:5294)
    at XhrConnection$XhrResponseHandler.onSuccess_1 [as onSuccess] (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:6236)
    at Xhr$Handler.onReadyStateChange (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:10084)
    at XMLHttpRequest.<anonymous> (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:1582)
    at apply_0 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:915)
    at entry0 (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:954)
    at XMLHttpRequest.<anonymous> (client-CCBEFD7AE81C773D56F894A9E41C3B4E.cache.js:942)
TobseF commented 3 years ago

The problem also occurs on a single UI just when reloading the page when the browser throttling is enabled. I checked this with the opened chrome developer tools with enabled caching. So it switching the UI or the page is not necessary to reproduce this error.

pleku commented 3 years ago

@TobseF so are these steps to reproduce ? 1) any MPR application running in production mode with frontend production build done 2) open an MPR UI which schedules a thread that soon updates the UI through ui.access 3) setup chrome to throttle the network connection to Fast-3G. 4) reload the page -> error appears on browser

And I would just like to note that in my opinion it makes no sense to test any application by throttling the network if the application doesn't behave like it should behave for the end user - with Flow applications this means that the frontend build has been done with build-frontend Maven/Gradle build goal. Running the webpack development server while throttling the network makes no sense to me. Enabling the vaadin.productionMode=true is can be left out, even though it would be enabled for end user.

TatuLund commented 3 years ago

Could this be linked to https://github.com/vaadin/multiplatform-runtime/issues/56

TobseF commented 3 years ago

@pleku

  1. Using prepare-frontent or production mode with build frontend doesn't matter. The problem occurs in both scenarios.
  2. Yes, the async call is the problem. I was able to force the error with this snippet:
    com.vaadin.ui.Label asyncReturn = new com.vaadin.ui.Label("Waiting...");
    UI ui = SampleUI.getCurrent();
    new Thread(() -> {
    System.out.println("Thread Start");
    ThreadUtils.sleep(100);
    ui.access(() -> {
      System.out.println("Here we are!");
      asyncReturn.setValue("Here we are!");
    });
    }).start();

    This is exactly which causes the exception as you can see the JS stacktrace: ⚡Uncaught TypeError: $0.firstElementChild.setResponse is not a function

2021-06-02_12h26_18 2021-06-02_12h21_57

For 3. and 4. Yes the reload wit fast-3G triggers the exception.

Our setup is the mentioned AppApplication. This adds our old legacy application to a V8 CssLayout which will be added to the AppApplication Div by add(new LegacyWrapper(legacyContent));. Our old application uses a HorizontalSplitPanel as main layout and uses the Navigator in combination with custom ViewProvider, ViewDisplay and NavigationStateManager to set its main content.

We also tried it with Transport.LONG_POLLING for @Push which also makes no difference.

To check out the resource loading, here is a bigger picture of the browser network tab in the error case: image (12)

pleku commented 3 years ago

Could this be linked to #56

No, but probably exactly the same as #13

mshabarov commented 3 years ago

I'm able to reproduce the same error by using popup-button test module/application and simply navigating to With Grid tab. Screenshot 2021-06-18 at 15 46 27

UPDATE:

It is only reproducible in dev mode. The root cause of this is the missing pom.xml configuration of popup-button module: vaadin maven plugin not set up

<plugin>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin-maven-plugin</artifactId>
</plugin>

and, thus, widget-set is not installed. This apparently causes an error during AbstractMprUIContentConnector initialisation, which prevent set up of setResponse function here addFunction(getConnection().getUIConnector().getWidget().getElement());.

This case has the same end result (setResponse function is not defined), but probably it's different from your root cause @TobseF. I'm not able to reproduce the issue with async request, but will try once more.

By the way, popup-button test module isn't even executed, because of missing maven failsafe plugin. The whole missing config is following:

           <plugin>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.vaadin</groupId>
                <artifactId>flow-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>prepare-frontend</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <productionMode>false</productionMode>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
            </plugin>

UPDATE: AbstractMprUIContentConnector code (and other client-side Java classes compiled into JS using GWT) is in {hash}.cache.js bundle. It's being initialised from AppWidgetset.nocache.js bundle and generated by vaadin-maven-plugin. If no vaadin-maven-plugin is set - there is no setResponse function available in the client side.

mshabarov commented 3 years ago

I used the following, but still not able to reproduce the issue:

  1. Use branch 2.0 of MPR project
  2. Use popup-button test module
  3. Added the plug-ins as described above.
  4. Add the following view:
@Route("test")
@LegacyUI(TestMainLayout.MyCustomUI.class)
@Push
public class TestMainLayout extends Div {

    public TestMainLayout() {
        com.vaadin.ui.Label legacyComponent = new com.vaadin.ui.Label(
                "Legacy component");
        add(new LegacyWrapper(legacyComponent));

        Div flowComponent = new Div();
        flowComponent.setText("Flow component");
        add(flowComponent);

        addAttachListener(event -> {
            com.vaadin.flow.component.UI ui = event.getUI();
            new Thread(() -> {
                System.out.println("Thread Start");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ignored) {
                }
                ui.access(() -> {
                    System.out.println("Here we are!");
                    legacyComponent.setValue("Legacy component changed");
                    flowComponent.setText("Flow component changed");
                });
            }).start();
        });
    }

    public static class MyCustomUI extends MprUI {
        @Override
        protected void init(VaadinRequest request) {
            super.init(request);
        }
    }
}
  1. Run the app, use both Fast-3G throttle and nothing, refresh the page many times. Everything works fine.
mshabarov commented 3 years ago

I managed to reproduce setResponse is not a function error (in ~5% of refreshes) with the same example as in my previous comment above, but with another delay: Thread.sleep(500);. It depends on the machine where this app is running. Here is a screenshot Screenshot 2021-06-24 at 8 38 34

It's not really visible on the Gantt diagram, but apparently ?v-r=push&v-uiId=... overlaps 5BC0122...cache.js in a way that the setResponse is called before the bundle completely loaded.

To reproduce:

  1. Checkout https://github.com/vaadin/multiplatform-runtime-internal/blob/86-reproduce/mpr-tests/popup-button/src/main/java/com/vaadin/mpr/TestMainLayout.java
  2. Run popup-button test application with mvn jetty:run
  3. Goto http://localhost:9998/test
  4. Refresh the page several times until you get an error as in the screenshot.
ZheSun88 commented 3 years ago

This fix has been released with platform 14.6.5

TobseF commented 3 years ago

Thanks for the platform release which to handle this bug. I tested the new 14.6.5 in our scenarios and indeed, the error message is gone. But the problem with the

"frozen UI". The page loads all content, but it never stops showing the loading indicator is still present.

So this fix doesn't change our situation, that the MPR cannot be used for our application. This bug is critical for us, because it challenges our whole invest of 6 months work of migration. It breaks about 100 of our Selenium-tests and it's still not clear if we can use the MPR at all.

Please reopen the issue, so we can investigate this problem further.

pleku commented 3 years ago

@TobseF the issue with the JS exception, caused by push-message processing before the client-engine was initialized, was fixed so it is probably something else that is causing the loading indicator to stay. Or then the fix was inadequate.

In case the fix was inadequate, then yes, this issue could be reopened. For us it means that we should be able to reproduce it the same way, which I understood is not the case. So to understand if the fix is valid or not, following things can be done: 1) You check in your project, when the loading indicator is still loading, that what does the $wnd.Vaadin.Flow.pendingResponses JavaScript object have as its values - if the push messages have been processed, then it should be empty. 2) If processing the response has failed, then there should be another JS exception shown instead. Do you see those in the console ? 3) In theory there could be also an issue with the timing of when the pending responses are processed, but I can verify this and write back here if that is the case.

In case it is another issue, then a new issue should be opened to this repository with new steps to reproduce the problem. In that case I think you can use the support portal to contact the expertise team for help in diagnosing and creating a new issue.

pleku commented 3 years ago

Based on another code review for the fix, @TobseF please wait until we double check that the fix is actually valid https://github.com/vaadin/multiplatform-runtime-internal/commit/ed3435c53d47a0f258b753020cf1ab45f102e735#r52907555 - I'm betting that in your case the initial UIDL response with the state has not been processed and thus the state is not correct when the push message is processed - which can have the effect that loading indicator stays present. However I would also expect that there are client side errors since the state on client side will in flux.

pleku commented 3 years ago

We concluded that the fix made is not correct, and thus reopened the issue. Not sure if it even breaks your application more, but there is a high chance for that. Sorry for the inconvenience, we're looking at this.

pleku commented 3 years ago

The second try to address the issue failed, but it is pretty clear now that the original fix (in Vaadin 14.6.5) is causing more problems when push is used immediately after the page was opened: when testing by refreshing the page, I see that the UI component will be in either a) the state after push - correct b) the initial state before the push - incorrect

pleku commented 3 years ago

Version 2.2.2 is now fixed and it should handle the issue with the push messages. Should be in a Vaadin 14.6 release tomorrow.

If you run into further issues with your project, please work with the expertise team to create a new issue that has the necessary code and steps to reproduce the problem.