1

I have a simple code, that imitate data processing after clicking a button:

@Route("long")
public class LongWait extends VerticalLayout {

    public LongWait() {
        Button processButton = new Button("Process");
        processButton.addClickListener(event -> process());
        add(processButton);
    }

    //imitates processing data: 
    //should sleep for 10 minutes and then add "finished" label
    //instead loose connection after 5 minutes
    private void process() {
        try {
            Thread.sleep(10 * 60 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        add(new Label("finished"));
    }
}


The problem is - browser loose connection with server after 5 minutes of "processing".

vaadin loose server connection

Why is it happening and how to avoid it?
(I really have to process large amount of data.)

Vaadin: 10.0.3
Tomcat: 9.0.8
Java: 1.8.0_162

UPD: After process() method have finished it's work (10 minutes passed) I got following error in log:

java.lang.UnsupportedOperationException: Confirmed duplicate message from the client. Expected sync id: 1, got 0. Message start: {"csrfToken":"964b296a-b3ab-48d2-b67f-5e46080f8949","rpc":[{"type":"event","node":4,"event":"click","data":{"event.shiftKey":false,"event.metaKey":false,"event.detail":1,"event.ctrlKey":false,"event.clientX":75,"event.clientY":42,"event.altKey":false,"event.button":0,"event.screenY":160,"event.screenX":76}}],"syncId":0,"clientId":0}
    at com.vaadin.flow.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:302)
    at com.vaadin.flow.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:89)
    at com.vaadin.flow.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40)
    at com.vaadin.flow.server.VaadinService.handleRequest(VaadinService.java:1487)
    at com.vaadin.flow.server.VaadinServlet.service(VaadinServlet.java:300)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:494)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:651)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:412)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:754)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1385)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
John
  • 467
  • 1
  • 6
  • 23

2 Answers2

6

What's happening here is that the button click listener is run directly from an HTTP request, for which there won't be any response until returning from the click listener. HTTP requests typically time out after one minute.

The best way of fixing this is usually to use the server push functionality provided by Vaadin. This would work so that the click handler starts the slow work in a separate thread and then immediately returns. Once the processing is completed, the results are separately pushed into the UI.

You can read an overview of how to do this in https://vaadin.com/docs/v10/flow/advanced/tutorial-push-access.html.

Leif Åstrand
  • 7,820
  • 13
  • 19
2

Thanks, @SteffenHarbich for suggest using a separate processing thread.
I used multithreading alongside Server Push and it worked flawlessly.

@Push
@Route("long")
public class LongWait extends VerticalLayout {

    private UI ui;

    public LongWait() {
        Button processButton = new Button("Process");
        processButton.addClickListener(event -> process());
        add(processButton);

        ui = UI.getCurrent();
    }

    //imitates processing data: 
    //sleeps for 10 minutes and then adds "finished" label
    private void process() {
        Thread thread = new Thread(() -> {

            try {
                Thread.sleep(10 * 60 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ui.access(() -> add(new Label("finished")));
            ui.push();
        });
        thread.start();
    }
}
John
  • 467
  • 1
  • 6
  • 23
  • 2
    One small tweak to this code example: you only need `ui.push()` when the push mode is explicitly configured as `MANUAL`. With the default `AUTOMATIC` setting, `push()` is automatically triggered after `access`, so there's no need to do it manually. – Leif Åstrand Aug 14 '18 at 11:33
  • 1
    I'd also recommend adding a detach listener that stops the thread if the component is detached before the thread has finished. – Leif Åstrand Aug 14 '18 at 11:34
  • This worked for us as well! (Vaadin 14.8.1) First we had the "Server con...reconnect..." error which was then followed by a "Resynchronizing UI by client's request" error. Moving our code from the listener into a thread solved both these problems! :) – Arnoud Aug 25 '22 at 08:00