diff options
author | Olli Tietäväinen <ollit@vaadin.com> | 2017-12-20 16:48:56 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-20 16:48:56 +0200 |
commit | 14a52da08932d6691815d19b31a81ba28bbbc711 (patch) | |
tree | bb457c22b05604ac0b88f67c156c242475ecec2a | |
parent | 22d20f67625e260f5f015ee691dcef476c58b8bd (diff) | |
download | vaadin-framework-14a52da08932d6691815d19b31a81ba28bbbc711.tar.gz vaadin-framework-14a52da08932d6691815d19b31a81ba28bbbc711.zip |
Prevent killing UI if heartbeats are pending (#10371) (#10450)
* Prevent killing UI if heartbeats are pending (#10371)
Fixes #9663
* fixed Java 1.8 syntax -> 1.6
3 files changed, 127 insertions, 5 deletions
diff --git a/server/src/main/java/com/vaadin/server/VaadinService.java b/server/src/main/java/com/vaadin/server/VaadinService.java index e453332f02..50dd55ee7a 100644 --- a/server/src/main/java/com/vaadin/server/VaadinService.java +++ b/server/src/main/java/com/vaadin/server/VaadinService.java @@ -1291,12 +1291,25 @@ public abstract class VaadinService implements Serializable { private boolean isUIActive(UI ui) { if (ui.isClosing()) { return false; - } else { - long now = System.currentTimeMillis(); - int timeout = 1000 * getHeartbeatTimeout(); - return timeout < 0 - || now - ui.getLastHeartbeatTimestamp() < timeout; } + + // Check for long running tasks + Lock lockInstance = ui.getSession().getLockInstance(); + if (lockInstance instanceof ReentrantLock) { + if (((ReentrantLock) lockInstance).hasQueuedThreads()) { + /* + * Someone is trying to access the session. Leaving all UIs + * alive for now. A possible kill decision will be made at a + * later time when the session access has ended. + */ + return true; + } + } + + // Check timeout + long now = System.currentTimeMillis(); + int timeout = 1000 * getHeartbeatTimeout(); + return timeout < 0 || now - ui.getLastHeartbeatTimestamp() < timeout; } /** diff --git a/uitest/src/main/java/com/vaadin/tests/core/LockingUI.java b/uitest/src/main/java/com/vaadin/tests/core/LockingUI.java new file mode 100644 index 0000000000..10f503b56c --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/core/LockingUI.java @@ -0,0 +1,62 @@ +package com.vaadin.tests.core; + +import com.vaadin.launcher.CustomDeploymentConfiguration; +import com.vaadin.launcher.CustomDeploymentConfiguration.Conf; +import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinService; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Notification.Type; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; + +@CustomDeploymentConfiguration({ + @Conf(name = "heartbeatInterval", value = "2") }) +public class LockingUI extends UI { + + public static final String LOCKING_ENDED = "Locking has ended"; + public static final String ALL_OK = "All is fine"; + + @Override + protected void init(VaadinRequest request) { + Button lockButton = new Button("Lock UI for too long", + new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + int heartbeatInterval = VaadinService.getCurrent() + .getDeploymentConfiguration() + .getHeartbeatInterval(); + try { + // Wait for 4 heartbeats + long timeout = heartbeatInterval * 1000; + for (int i = 0; i < 4; ++i) { + Thread.sleep(timeout); + } + + } catch (InterruptedException e1) { + throw new RuntimeException( + "Timeout should not get interrupted."); + } + Notification.show(LOCKING_ENDED, + Type.TRAY_NOTIFICATION); + } + }); + Button checkButton = new Button("Test communication", + new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + Notification.show(ALL_OK, Type.TRAY_NOTIFICATION); + } + }); + + lockButton.setId("lock"); + checkButton.setId("check"); + + setContent(new VerticalLayout(lockButton, checkButton)); + } + +} diff --git a/uitest/src/test/java/com/vaadin/tests/core/LockingUITest.java b/uitest/src/test/java/com/vaadin/tests/core/LockingUITest.java new file mode 100644 index 0000000000..214adfc94d --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/core/LockingUITest.java @@ -0,0 +1,47 @@ +package com.vaadin.tests.core; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.NotificationElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class LockingUITest extends SingleBrowserTest { + + @Test + public void testLockingTheUIFor4HeartBeats() { + openTestURL(); + + clickButtonAndCheckNotification("check", LockingUI.ALL_OK); + clickButtonAndCheckNotification("lock", LockingUI.LOCKING_ENDED); + clickButtonAndCheckNotification("check", LockingUI.ALL_OK); + } + + private void clickButtonAndCheckNotification(String buttonId, String text) { + checkNoInitialNotification(); + + $(ButtonElement.class).id(buttonId).click(); + testBench().waitForVaadin(); + + checkNotification(text); + } + + private void checkNotification(String text) { + assertTrue("Notification should be displayed", + $(NotificationElement.class).exists()); + + NotificationElement notification = $(NotificationElement.class).first(); + assertEquals("Unexpected text content in Notification", text, + notification.getText()); + notification.close(); + } + + private void checkNoInitialNotification() { + assertFalse("Extra notification displayed", + $(NotificationElement.class).exists()); + } +} |