Add ability to handle a timeout to DeferredResult

When a controller returns a DeferredResult, the underlying async
request will eventually time out. Until now the default behavior was
to send a 503 (SERVICE_UNAVAILABLE). However, this is not desirable
in all cases. For example if waiting on an event, a timeout simply
means there is no new information to send.

To handle those cases a DeferredResult now accespts a timeout result
Object in its constructor. If the timeout occurs before the
DeferredResult is set, the timeout result provided to the constructor
is used instead.

Issue: SPR-8617
This commit is contained in:
Rossen Stoyanchev
2012-04-26 17:38:31 -04:00
parent f37efb4279
commit 7ee821d3d1
8 changed files with 272 additions and 55 deletions

View File

@@ -123,7 +123,7 @@ public class AsyncExecutionChainTests {
fail("Expected exception");
}
catch (IllegalStateException ex) {
assertThat(ex.getMessage(), containsString("The callable field is required"));
assertThat(ex.getMessage(), containsString("last callable is required"));
}
}
@@ -171,7 +171,7 @@ public class AsyncExecutionChainTests {
fail("Expected exception");
}
catch (IllegalArgumentException ex) {
assertThat(ex.getMessage(), containsString("A DeferredResult is required"));
assertThat(ex.getMessage(), containsString("DeferredResult is required"));
}
}
@@ -186,6 +186,10 @@ public class AsyncExecutionChainTests {
super(request, response);
}
public void setTimeout(Long timeout) { }
public void setTimeoutHandler(Runnable runnable) { }
public void startAsync() {
this.asyncStarted = true;
}
@@ -194,8 +198,6 @@ public class AsyncExecutionChainTests {
return this.asyncStarted;
}
public void setTimeout(Long timeout) { }
public void complete() {
this.asyncStarted = false;
this.asyncCompleted = true;

View File

@@ -0,0 +1,119 @@
/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.context.request.async;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reset;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.springframework.web.context.request.async.DeferredResult.DeferredResultHandler;
/**
* DeferredResult tests.
*
* @author Rossen Stoyanchev
*/
public class DeferredResultTests {
@Test
public void canHandleTimeout() {
assertFalse(new DeferredResult().canHandleTimeout());
assertTrue(new DeferredResult("foo").canHandleTimeout());
}
@Test
public void set() {
DeferredResultHandler resultHandler = createMock(DeferredResultHandler.class);
DeferredResult deferredResult = new DeferredResult();
deferredResult.init(resultHandler);
resultHandler.handle("foo");
replay(resultHandler);
deferredResult.set("foo");
verify(resultHandler);
}
@Test
public void handleTimeout() {
DeferredResultHandler resultHandler = createMock(DeferredResultHandler.class);
DeferredResult deferredResult = new DeferredResult("foo");
deferredResult.init(resultHandler);
resultHandler.handle("foo");
replay(resultHandler);
deferredResult.handleTimeout();
verify(resultHandler);
}
@Test(expected=IllegalStateException.class)
public void handleTimeout_timeoutResultNone() {
new DeferredResult().handleTimeout();
}
@Test
public void setAfterHandleTimeout() {
DeferredResultHandler resultHandler = createMock(DeferredResultHandler.class);
DeferredResult deferredResult = new DeferredResult("foo");
deferredResult.init(resultHandler);
resultHandler.handle("foo");
replay(resultHandler);
deferredResult.handleTimeout();
verify(resultHandler);
try {
deferredResult.set("foo");
fail("Expected exception");
}
catch (StaleAsyncWebRequestException ex) {
// expected
}
}
@Test
public void setBeforeHandleTimeout() {
DeferredResultHandler resultHandler = createMock(DeferredResultHandler.class);
DeferredResult deferredResult = new DeferredResult("foo");
deferredResult.init(resultHandler);
resultHandler.handle("foo");
replay(resultHandler);
deferredResult.set("foo");
verify(resultHandler);
reset(resultHandler);
replay(resultHandler);
deferredResult.handleTimeout();
verify(resultHandler);
}
}