aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlli Tietäväinen <ollit@vaadin.com>2017-12-20 16:48:56 +0200
committerGitHub <noreply@github.com>2017-12-20 16:48:56 +0200
commit14a52da08932d6691815d19b31a81ba28bbbc711 (patch)
treebb457c22b05604ac0b88f67c156c242475ecec2a
parent22d20f67625e260f5f015ee691dcef476c58b8bd (diff)
downloadvaadin-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
-rw-r--r--server/src/main/java/com/vaadin/server/VaadinService.java23
-rw-r--r--uitest/src/main/java/com/vaadin/tests/core/LockingUI.java62
-rw-r--r--uitest/src/test/java/com/vaadin/tests/core/LockingUITest.java47
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());
+ }
+}