Add check for unused WebSocket sessions

Sessions connected to a STOMP endpoint are expected to receive some
client messages. Having received none after successfully connecting
could be an indication of proxy or network issue. This change adds
periodic checks to see if we have not received any messages on a
session which is an indication the session isn't going anywhere
most likely due to a proxy issue (or unreliable network) and close
those sessions.

Issue: SPR-11884
This commit is contained in:
Rossen Stoyanchev
2014-06-26 09:38:46 -04:00
parent 98d6f7b443
commit a3fa9c9797
2 changed files with 153 additions and 21 deletions

View File

@@ -17,16 +17,24 @@
package org.springframework.web.socket.messaging;
import java.util.Arrays;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator;
import org.springframework.web.socket.handler.TestWebSocketSession;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;
/**
@@ -56,11 +64,9 @@ public class SubProtocolWebSocketHandlerTests {
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.webSocketHandler = new SubProtocolWebSocketHandler(this.inClientChannel, this.outClientChannel);
when(stompHandler.getSupportedProtocols()).thenReturn(Arrays.asList("v10.stomp", "v11.stomp", "v12.stomp"));
when(mqttHandler.getSupportedProtocols()).thenReturn(Arrays.asList("MQTT"));
this.session = new TestWebSocketSession();
this.session.setId("1");
}
@@ -140,4 +146,32 @@ public class SubProtocolWebSocketHandlerTests {
this.webSocketHandler.afterConnectionEstablished(session);
}
@Test
public void checkSession() throws Exception {
TestWebSocketSession session1 = new TestWebSocketSession("id1");
TestWebSocketSession session2 = new TestWebSocketSession("id2");
session1.setAcceptedProtocol("v12.stomp");
session2.setAcceptedProtocol("v12.stomp");
this.webSocketHandler.setProtocolHandlers(Arrays.asList(this.stompHandler));
this.webSocketHandler.afterConnectionEstablished(session1);
this.webSocketHandler.afterConnectionEstablished(session2);
session1.setOpen(true);
session2.setOpen(true);
long sixtyOneSecondsAgo = System.currentTimeMillis() - 61 * 1000;
new DirectFieldAccessor(this.webSocketHandler).setPropertyValue("lastSessionCheckTime", sixtyOneSecondsAgo);
Map<String, ?> sessions = (Map<String, ?>) new DirectFieldAccessor(this.webSocketHandler).getPropertyValue("sessions");
new DirectFieldAccessor(sessions.get("id1")).setPropertyValue("createTime", sixtyOneSecondsAgo);
new DirectFieldAccessor(sessions.get("id2")).setPropertyValue("createTime", sixtyOneSecondsAgo);
this.webSocketHandler.handleMessage(session1, new TextMessage("foo"));
assertTrue(session1.isOpen());
assertFalse(session2.isOpen());
assertNull(session1.getCloseStatus());
assertEquals(CloseStatus.PROTOCOL_ERROR, session2.getCloseStatus());
}
}