AMQ-9481 - Correctly complete async servlet request on timeout

This fixes AsyncServletRequest to correctly call context.dispatch() when
the async request times out so that the consumer can be re-used.
This commit is contained in:
Christopher L. Shannon 2024-04-21 12:42:20 -04:00
parent 6084867b26
commit 72befc14fb
2 changed files with 17 additions and 8 deletions

View File

@ -86,11 +86,20 @@ public class RestTest extends JettyTestSupport {
HttpClient httpClient = new HttpClient();
httpClient.start();
final StringBuffer buf = new StringBuffer();
final Future<Result> result =
asyncRequest(httpClient, "http://localhost:" + port + "/message/test?readTimeout=1000&type=queue", buf);
// AMQ-9330 - test no 500 error on timeout and instead 204 error
Future<Result> result =
asyncRequest(httpClient, "http://localhost:" + port + "/message/test?readTimeout=2000&type=queue&clientId=test", new StringBuffer());
// try a second request while the first is running, this should get a 500 error since the first is still running and
// concurrent access to the same consumer is not allowed
Future<Result> errorResult = asyncRequest(httpClient, "http://localhost:" + port + "/message/test?readTimeout=1&type=queue&clientId=test", new StringBuffer());
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR_500, errorResult.get().getResponse().getStatus());
//After the original request finishes, verify 204 and not 500 error
assertEquals(HttpStatus.NO_CONTENT_204, result.get().getResponse().getStatus());
//Test timeout, no message was sent
// AMQ-9481 - test to make sure we can re-use the consumer after timeout by trying again and ensuring
// no 500 error. Before the fix in AMQ-9418 this would fail even after the previous request timed out
result =
asyncRequest(httpClient, "http://localhost:" + port + "/message/test?readTimeout=1000&type=queue&clientId=test", new StringBuffer());
assertEquals(HttpStatus.NO_CONTENT_204, result.get().getResponse().getStatus());
}

View File

@ -115,10 +115,10 @@ public class AsyncServletRequest implements AsyncListener {
}
final AsyncContext context = event.getAsyncContext();
if (context != null) {
// We must call complete and then set the status code to prevent a 500
// error. The spec requires a 500 error on timeout unless complete() is called.
context.complete();
if (context != null && event.getSuppliedRequest().isAsyncStarted()) {
// We must call dispatch to finish the request on timeout.
// then set the status code to prevent a 500 error.
context.dispatch();
final ServletResponse response = context.getResponse();
if (response instanceof HttpServletResponse) {
((HttpServletResponse) response).setStatus(HttpServletResponse.SC_NO_CONTENT);