OverflowStrategy in ConcurrentWebSocketSessionDecorator

Issue: SPR-17140
This commit is contained in:
Rossen Stoyanchev
2018-08-10 16:14:22 +03:00
parent 61c52d64c5
commit 309ffc6d0d
2 changed files with 95 additions and 9 deletions

View File

@@ -52,6 +52,8 @@ public class ConcurrentWebSocketSessionDecorator extends WebSocketSessionDecorat
private final int bufferSizeLimit;
private final OverflowStrategy overflowStrategy;
private final Queue<WebSocketMessage<?>> buffer = new LinkedBlockingQueue<>();
private final AtomicInteger bufferSize = new AtomicInteger();
@@ -68,15 +70,31 @@ public class ConcurrentWebSocketSessionDecorator extends WebSocketSessionDecorat
/**
* Create a new {@code ConcurrentWebSocketSessionDecorator}.
* Basic constructor.
* @param delegate the {@code WebSocketSession} to delegate to
* @param sendTimeLimit the send-time limit (milliseconds)
* @param bufferSizeLimit the buffer-size limit (number of bytes)
*/
public ConcurrentWebSocketSessionDecorator(WebSocketSession delegate, int sendTimeLimit, int bufferSizeLimit) {
this(delegate, sendTimeLimit, bufferSizeLimit, OverflowStrategy.TERMINATE);
}
/**
* Constructor that also specifies the overflow strategy to use.
* @param delegate the {@code WebSocketSession} to delegate to
* @param sendTimeLimit the send-time limit (milliseconds)
* @param bufferSizeLimit the buffer-size limit (number of bytes)
* @param overflowStrategy the overflow strategy to use; by default the
* session is terminated.
* @since 5.1
*/
public ConcurrentWebSocketSessionDecorator(
WebSocketSession delegate, int sendTimeLimit, int bufferSizeLimit, OverflowStrategy overflowStrategy) {
super(delegate);
this.sendTimeLimit = sendTimeLimit;
this.bufferSizeLimit = bufferSizeLimit;
this.overflowStrategy = overflowStrategy;
}
@@ -148,7 +166,7 @@ public class ConcurrentWebSocketSessionDecorator extends WebSocketSessionDecorat
if (message == null || shouldNotSend()) {
break;
}
this.bufferSize.addAndGet(message.getPayloadLength() * -1);
this.bufferSize.addAndGet(-message.getPayloadLength());
this.sendStartTime = System.currentTimeMillis();
getDelegate().sendMessage(message);
this.sendStartTime = 0;
@@ -167,14 +185,35 @@ public class ConcurrentWebSocketSessionDecorator extends WebSocketSessionDecorat
if (!shouldNotSend() && this.closeLock.tryLock()) {
try {
if (getTimeSinceSendStarted() > getSendTimeLimit()) {
String format = "Message send time %d (ms) for session '%s' exceeded the allowed limit %d";
String format = "Send time %d (ms) for session '%s' exceeded the allowed limit %d";
String reason = String.format(format, getTimeSinceSendStarted(), getId(), getSendTimeLimit());
limitExceeded(reason);
}
else if (getBufferSize() > getBufferSizeLimit()) {
String format = "The send buffer size %d bytes for session '%s' exceeded the allowed limit %d";
String reason = String.format(format, getBufferSize(), getId(), getBufferSizeLimit());
limitExceeded(reason);
switch (this.overflowStrategy) {
case TERMINATE:
String format = "Buffer size %d bytes for session '%s' exceeds the allowed limit %d";
String reason = String.format(format, getBufferSize(), getId(), getBufferSizeLimit());
limitExceeded(reason);
break;
case DROP:
int i = 0;
while (getBufferSize() > getBufferSizeLimit()) {
WebSocketMessage<?> message = this.buffer.poll();
if (message == null) {
break;
}
this.bufferSize.addAndGet(-message.getPayloadLength());
i++;
}
if (logger.isDebugEnabled()) {
logger.debug("Dropped " + i + " messages, buffer size: " + getBufferSize());
}
break;
default:
// Should never happen..
throw new IllegalStateException("Unexpected OverflowStrategy: " + this.overflowStrategy);
}
}
}
finally {
@@ -223,4 +262,23 @@ public class ConcurrentWebSocketSessionDecorator extends WebSocketSessionDecorat
return getDelegate().toString();
}
/**
* Enum for options of what to do when the buffer fills up.
* @since 5.1
*/
public enum OverflowStrategy {
/**
* Throw {@link SessionLimitExceededException} that would will result
* in the session being terminated.
*/
TERMINATE,
/**
* Drop the oldest messages from the buffer.
*/
DROP
}
}