UI polling - "No such connector could be found. Resynchronized client."

Hi.

I am currently replacing use of the Refresher add-on in our application with the new UI polling.

When I enabled the polling - UI.setPollInterval(1000) - I am in a vaadin request/response thread.
When I disable the polling - UI.setPollInterval(-1) - I am in a background thread, but the disabling is done within a lock of the session:

[size=2]
[font=courier new]
VaadinSession.getCurrent().lock();

try
{
session.getUI().setPollInterval(-1);
}
finally
{
VaadinSession.getCurrent().unlock();
}
[/font]
[/size]

If the background thread is quick, then I
always
get the following warning messages in the console:

“com.vaadin.server.communication.ServerRpcHandler parseInvocation WARNING: RPC call to v.v received for connector but no such connector could be found. Resynchronizing client.”

If the background thread takes a little bit of time, then no such warning occurs.

Am I doing something wrong, or is this a known issue/bug? There is no impact on the application, just warnings to be explained away to customers.

EDIT: I forced in a little sleep in my background thread to make it run just longer than the poll interval. When I do this, no warning messages. Is it possible this warning is raised whenever a poll interval is activated, but then deactivated before it’s even performed the first poll?

Any takers this fine morning?

Interesting. Could you provide a minimal test case? A single UI class if possible.

Do you do anything else at the same time as you disable the poll request? And what is Connector ? The UI or something else?

The “v.v” call indicates that there is something on the client side sending a legacy variable update to the server side and when this update reaches the server, the target connector (component) is no longer attached to the UI.

Hi guys.

Well, apologies, for this may not be a vaadin bug after all (at least, as I have described). However, if you could still take the time to read this reply, I would be grateful!

I did as asked, and wrote a very small app that would replicate the issue if the bug was as simple as I have said. Alas, vaadin acted perfectly…

[font=courier new]
[size=2]

import com.vaadin.annotations.PreserveOnRefresh;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.TextField;
import com.vaadin.ui.UI;

@PreserveOnRefresh
public class TestUI extends UI
{    
    private Button button;
    private TextField pollTextField;
    private TextField threadTextField;
    
    @Override
    public void init(VaadinRequest vaadinRequest)
    {         
        HorizontalLayout hl = new HorizontalLayout();
        hl.setSizeUndefined();
        button = new Button("Start Server Thread", new Button.ClickListener()
        {            
            @Override
            public void buttonClick(ClickEvent event)
            {
                int pollValue = Integer.parseInt(pollTextField.getValue());
                int threadValue = Integer.parseInt(threadTextField.getValue());
                
                setPollInterval(pollValue);                
                startServerThread(threadValue);
                button.setCaption("Running Server Thread...");
            }
        });
        
        button.setSizeUndefined();
        button.setDisableOnClick(true);
        
        hl.addComponent(button);
        
        pollTextField = new TextField("Poll interval");
        pollTextField.setValue("1000");
        pollTextField.setSizeUndefined();
        
        hl.addComponent(pollTextField);
        
        threadTextField = new TextField("Thread length");
        threadTextField.setValue("5000");
        threadTextField.setSizeUndefined();
        
        hl.addComponent(threadTextField);                                
        
        // Building the window is separated from the application initialization 
        setContent(hl);       
        setSizeFull();
    }
    
    private void startServerThread(final int threadValue)
    {
        Thread thread = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                // TODO Auto-generated method stub
                if (threadValue > 0)
                {
                    try
                    {
                        Thread.sleep(threadValue);
                    }
                    catch (Exception e)
                    {                    
                    }
                }
                
                VaadinSession.getCurrent().lock();
                try
                {
                    button.setCaption("Start Server Thread");
                    button.setEnabled(true);
                    
                    System.out.println("Disabling poll interval");
                    setPollInterval(-1);
                }
                finally
                {
                    VaadinSession.getCurrent().unlock();
                }
            }            
        });
        
        thread.start();
    }      
}

[/size]
[/font]

[font=arial]
[size=3]
So I tried again. This time I introduced our workflow, simplified as much as possible, and it displays the problem.

To replicate, set the poll interval greater than the server thread length.

The difference here is that we have a abstract class (
Poller
) responsible for starting/stopping the polling, and a default implementation (
DefaultPoller
)[b]

[/b]that throws up a modal dialog when polling starts (to prevent user access during the long-running server thread), and remove it again when polling is complete.

The poller is started in a button click, and is stopped in the server thread (wrapped in a vaadin session lock).

The exact same mechanism was used for the Refresher add-on, and it threw no exceptions in the log. Its only when we replaced the Refresher add-on with UI.setPollInterval() that the exceptions started being thrown.

I can’t see the problem. Maybe I misunderstand something in Vaadin? Maybe I’ve just been looking at the same code too long? Any help would be greatly appreciated.

Cheers,
Lee.
[/size]
[/font]

import com.vaadin.annotations.PreserveOnRefresh;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.TextField;
import com.vaadin.ui.UI;
import com.vaadin.ui.Window;

@PreserveOnRefresh
public class ParametersApplication extends UI
{    
    private Button button;
    private TextField pollTextField;
    private TextField threadTextField;
    
    private DefaultPoller poller;
    
    @Override
    public void init(VaadinRequest vaadinRequest)
    {         
        HorizontalLayout hl = new HorizontalLayout();
        hl.setSizeUndefined();
        button = new Button("Start Server Thread", new Button.ClickListener()
        {            
            @Override
            public void buttonClick(ClickEvent event)
            {
                int pollValue = Integer.parseInt(pollTextField.getValue());
                int threadValue = Integer.parseInt(threadTextField.getValue());
                                
                try
                {
                    poller.start(pollValue);
                }
                catch (Exception e)
                {
                    return;
                }
                
                startServerThread(threadValue);
                
                button.setCaption("Running Server Thread...");
            }
        });
        
        button.setSizeUndefined();
        button.setDisableOnClick(true);
        
        hl.addComponent(button);
        
        pollTextField = new TextField("Poll interval");
        pollTextField.setValue("1000");
        pollTextField.setSizeUndefined();
        
        hl.addComponent(pollTextField);
        
        threadTextField = new TextField("Thread length");
        threadTextField.setValue("5000");
        threadTextField.setSizeUndefined();
        
        hl.addComponent(threadTextField);                                
        
        poller = new DefaultPoller();
        
        // Building the window is separated from the application initialization 
        setContent(hl);       
        setSizeFull();
    }
    
    private void startServerThread(final int threadValue)
    {
        Thread thread = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                if (threadValue > 0)
                {
                    try
                    {
                        Thread.sleep(threadValue);
                    }
                    catch (Exception e)
                    {                    
                    }
                }
                
                poller.stopOk();
                
                button.setCaption("Start Server Thread");
                button.setEnabled(true);                    
            }            
        });
        
        thread.start();
    }     
    
    public static class Poller
    {
        public enum PollerStatus {INACTIVE, RUNNING};                
        private PollerStatus status = PollerStatus.INACTIVE;        
                    
        public Poller()
        {
            // initial status
            status = PollerStatus.INACTIVE;        
        }
        
        public synchronized void start(int refreshInterval) throws Exception
        {
            if (UI.getCurrent().getPollInterval() != -1 && status != PollerStatus.RUNNING)
            {
                throw new Exception("Another process has started UI polling");
            }
            
            if (status == PollerStatus.INACTIVE)
            {             
                // set status to running beore calling onStarted() - not that it really matters
                status = PollerStatus.RUNNING;
                
                // Catch any exception thrown within onStarted() [custom code]
. This will in effect
                // abort the start process.
                try
                {
                    onStarted();                
                }
                catch (Throwable t)
                {                
                    // revert status back to inactive and rethrow exception
                    status = PollerStatus.INACTIVE;
                    throw new Exception(t);
                }
                                            
                System.out.println("Starting UI polling with interval of " + refreshInterval);
                UI.getCurrent().setPollInterval(refreshInterval);
            }
            else
            {
                throw new Exception("UI polling is still active");
            }
        }
        
        public synchronized void stopOk()
        {                 
            // NOTE - this is most likely called from a seperate thread from outwith the request/responose cycle.
            // Synchronize on the vaadin application              
            VaadinSession.getCurrent().lock();
            
            try
            {  
                if (status == PollerStatus.RUNNING)
                {
                    status = PollerStatus.INACTIVE;
                    
                    onFinishedOk();                    
                
                    System.out.println("Disabling UI polling");                    
                    UI.getCurrent().setPollInterval(-1);
                }
            }
            finally
            {
                VaadinSession.getCurrent().unlock();
            }
        }
              
        /**
         * Called when polling started.
         * Overwrite as required to do something useful.
         * It is safe to update the UI in this call.
         */
        protected synchronized void onStarted()
        {        
        }
        
        /**
         * Called at the next poll after it has been informed to stop via a call to stopOk().
         * Overwrite as required to do something useful.
         * It is safe to update the UI in this call.
         */ 
        protected synchronized void onFinishedOk()
        {
        }        
    }
    
    public static class DefaultPoller extends Poller
    {
        private Window dialogWindow;
                                        
        // Polling started - show modal dialog
        protected synchronized void onStarted()
        {                
            // create dialog
            dialogWindow = new Window();                        
            dialogWindow.setModal(true);
            dialogWindow.setClosable(false);
            dialogWindow.setResizable(false);
            dialogWindow.setDraggable(false);            
            dialogWindow.setSizeUndefined();
                    
            // message label
            Label defaultMessageLabel = new Label("   Please Wait...   ");
            defaultMessageLabel.setSizeUndefined();                        
            dialogWindow.setContent(defaultMessageLabel);

            // add the dialog
            UI.getCurrent().addWindow(dialogWindow);            
            dialogWindow.focus();                  
        }
                
        // polling finished - remove modal dialog
        protected synchronized void onFinishedOk()
        {
            UI.getCurrent().removeWindow(dialogWindow);
            dialogWindow = null;    
        }                       
    }
}

If you run your server with the -ea JVM parameter you will see that you do not lock the session in your background thread when doing

button.setCaption("Start Server Thread");
button.setEnabled(true);

Hi Artur

Apologies for that! Our production code doesnt do that, that was just me making an error when trimming everything back to the bare bones.

Here is the corrected code which still displays the problem. Run with default values, and you will see the warnings in the log. Increase the thread time to greater than the poll time, and the warnings never appear.

Your continued help is greatly appreciated!

Cheers,
Lee.

import com.vaadin.annotations.PreserveOnRefresh;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.TextField;
import com.vaadin.ui.UI;
import com.vaadin.ui.Window;

@PreserveOnRefresh
public class TestUI extends UI
{    
    private Button button;
    private TextField pollTextField;
    private TextField threadTextField;
    
    private DefaultPoller poller;
    
    @Override
    public void init(VaadinRequest vaadinRequest)
    {         
        HorizontalLayout hl = new HorizontalLayout();
        hl.setSizeUndefined();
        button = new Button("Start Server Thread", new Button.ClickListener()
        {            
            @Override
            public void buttonClick(ClickEvent event)
            {
                int pollValue = Integer.parseInt(pollTextField.getValue());
                int threadValue = Integer.parseInt(threadTextField.getValue());
                                
                try
                {
                    poller.start(pollValue);
                }
                catch (Exception e)
                {
                    return;
                }
                
                startServerThread(threadValue);
                
                button.setCaption("Running Server Thread...");
            }
        });
        
        button.setSizeUndefined();
        button.setDisableOnClick(true);
        
        hl.addComponent(button);
        
        pollTextField = new TextField("Poll interval");
        pollTextField.setValue("1000");
        pollTextField.setSizeUndefined();
        
        hl.addComponent(pollTextField);
        
        threadTextField = new TextField("Thread length");
        threadTextField.setValue("500");
        threadTextField.setSizeUndefined();
        
        hl.addComponent(threadTextField);                                
        
        poller = new DefaultPoller();
        
        // Building the window is separated from the application initialization 
        setContent(hl);       
        setSizeFull();
    }
    
    private void startServerThread(final int threadValue)
    {
        Thread thread = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                if (threadValue > 0)
                {
                    try
                    {
                        Thread.sleep(threadValue);
                    }
                    catch (Exception e)
                    {                    
                    }
                }
                
                // NOTE - this is most likely called from a seperate thread from outwith the request/responose cycle.
                // Synchronize on the vaadin application              
                VaadinSession.getCurrent().lock();
                
                try
                {                  
                    poller.stopOk();
                    
                    button.setCaption("Start Server Thread");
                    button.setEnabled(true);
                }
                finally
                {
                    VaadinSession.getCurrent().unlock();
                }
            }            
        });
        
        thread.start();
    }     
    
    public static class Poller
    {
        public enum PollerStatus {INACTIVE, RUNNING};                
        private PollerStatus status = PollerStatus.INACTIVE;        
                    
        public Poller()
        {
            // initial status
            status = PollerStatus.INACTIVE;        
        }
        
        public synchronized void start(int refreshInterval) throws Exception
        {
            if (UI.getCurrent().getPollInterval() != -1 && status != PollerStatus.RUNNING)
            {
                throw new Exception("Another process has started UI polling");
            }
            
            if (status == PollerStatus.INACTIVE)
            {             
                // set status to running beore calling onStarted() - not that it really matters
                status = PollerStatus.RUNNING;
                
                // Catch any exception thrown within onStarted() [custom code]
. This will in effect
                // abort the start process.
                try
                {
                    onStarted();                
                }
                catch (Throwable t)
                {                
                    // revert status back to inactive and rethrow exception
                    status = PollerStatus.INACTIVE;
                    throw new Exception(t);
                }
                                            
                System.out.println("Starting UI polling with interval of " + refreshInterval);
                UI.getCurrent().setPollInterval(refreshInterval);
            }
            else
            {
                throw new Exception("UI polling is still active");
            }
        }
        
        public synchronized void stopOk()
        {                 
            if (status == PollerStatus.RUNNING)
            {
                status = PollerStatus.INACTIVE;
                
                onFinishedOk();                    
            
                System.out.println("Disabling UI polling");                    
                UI.getCurrent().setPollInterval(-1);
            }
        }
              
        /**
         * Called when polling started.
         * Overwrite as required to do something useful.
         */
        protected synchronized void onStarted()
        {        
        }
        
        /**
         * Called at the next poll after it has been informed to stop via a call to stopOk().
         * Overwrite as required to do something useful.
         */ 
        protected synchronized void onFinishedOk()
        {
        }        
    }
    
    public static class DefaultPoller extends Poller
    {
        private Window dialogWindow;
                                        
        // Polling started - show modal dialog
        protected synchronized void onStarted()
        {                
            // create dialog
            dialogWindow = new Window();                        
            dialogWindow.setModal(true);
            dialogWindow.setClosable(false);
            dialogWindow.setResizable(false);
            dialogWindow.setDraggable(false);            
            dialogWindow.setSizeUndefined();
                    
            // message label
            Label defaultMessageLabel = new Label("Please Wait...");
            defaultMessageLabel.setSizeUndefined();                        
            dialogWindow.setContent(defaultMessageLabel);

            // add the dialog
            UI.getCurrent().addWindow(dialogWindow);            
            dialogWindow.focus();                  
        }
                
        // polling finished - remove modal dialog
        protected synchronized void onFinishedOk()
        {
            UI.getCurrent().removeWindow(dialogWindow);
            dialogWindow = null;    
        }                       
    }
}

Shameless bump for attention…

I too get this logged twice every time a user logs into my application. I just set call super.setPollInterval(30000); from my UI.init() method, and never change it.

In the servelt, I also have heartbeatInterval set to 60, and I’m using the Refresher extension from the wiki, since the UI poller doesn’t include a listener.

I removed the call to setPollInterval(), but the warnings still appear.

Oh, this seems to be a legitimate bug, though a harmless one.

It’s the dialog window that’s referred to by the warning message. WindowConnector sends the actual pixel coordinates of the window back to the server as a non-immediate variable change. They get sent in the next polling request, but at that point the Window is already closed on server side – but the closing is not yet communicated to the client! So the warning is in principle correct - the server and client are out of sync, but this is not indicative of an actual error condition and should be handled more gracefully.

This could of course happen with other components too, as long as there are some non-immediate changes on the client side when the component is concurrently removed on the server side.

As an aside, surely you should not use UI polling if you also have a Refresher? But yes, probably the same issue.

Thanks Johannes, that answers the problem!

Im guessing, at least in my case, thay the WindowConnector variable change is sent only in the first poll, and would explain why I dont see the messages being logged if the server thread takes longer than the poll interval.

Is it something Vaadin could detect and handle more gracefully? If so, I’ll raise a (minor) ticket accordingly. If not, I guess we will have to live with it. Or revert back to using the Refresher - we don’t see the problem with that as we close the window only when the refresher polls via its listener mechanism.

I guess waiting for 7.2, when you plan to have a listener mechanism on your UI polling, is another option :slight_smile:

Cheers,
Lee.

Yes, Vaadin actually already knows that the removal isn’t communicated to the client yet, so it would be straightforward to add a check. However, I’m not entirely sure it’s a good idea to always simply ignore the situation - in this case it’s trivially the right thing to do, but what if the client message contains some important information supplied by the user? I suppose that in the end it’s the individual application’s responsibility to never do things like asynchronously removing field components that might have unsent changes on the client side.

As a compromise, the log message could be downgraded from a warning to a debug message hidden by default.

BTW, I’m very surprised if this exact same thing doesn’t occur when using Refresher instead of the builtin polling. From the server’s point of view, the mechanisms are identical.

Johannes.

When we use the Refresher, we were working in its listener mechanism. That is, we only ever removed the dialog DURING a refresher poll. I would imagine that during that poll, Vaadin acts upon the variable change for the window connector before we remove the dialog, and therefore never any warning as they are in sync!

Using UI polling, we don’t know when the poll is actually happening, and so close the dialog immediatley upon the server thread finishing.

Cheeers,
Lee.

Ah, right, that makes sense.

Opened
ticket #12909
.

Greatly appreciated - thanks for all your help!

I was originally trying to use the UI poll listener until I found the Refresher extension in the wiki. I commented out the UI.setPollInterval() call yesterday, but the warnings are still logged.