From bdccd90150d95f81d40d3dc788e9b30adee24659 Mon Sep 17 00:00:00 2001 From: injae-kim Date: Fri, 5 Jan 2024 21:08:34 +0900 Subject: [PATCH] Fix `AsyncContext` to be completed on `AsyncListener.onError()` Closes gh-31541 --- .../async/StandardServletAsyncWebRequest.java | 3 ++ .../StandardServletAsyncWebRequestTests.java | 33 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java b/spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java index eb46ccb64790..c883c8e8a9df 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java @@ -151,6 +151,9 @@ public void onTimeout(AsyncEvent event) throws IOException { @Override public void onError(AsyncEvent event) throws IOException { + if (this.asyncContext != null) { + this.asyncContext.complete(); + } this.exceptionHandlers.forEach(consumer -> consumer.accept(event.getThrowable())); } diff --git a/spring-web/src/test/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequestTests.java b/spring-web/src/test/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequestTests.java index c27202ed98e2..b687e169b126 100644 --- a/spring-web/src/test/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequestTests.java +++ b/spring-web/src/test/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequestTests.java @@ -16,9 +16,12 @@ package org.springframework.web.context.request.async; +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import jakarta.servlet.AsyncEvent; +import jakarta.servlet.AsyncListener; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -124,6 +127,36 @@ public void onErrorHandler() throws Exception { verify(errorHandler).accept(e); } + @Test + public void onErrorShouldCompleteAsyncContext() throws Exception { + this.asyncRequest.startAsync(); + AtomicInteger completeCounter = new AtomicInteger(); + MockAsyncContext context = (MockAsyncContext) this.request.getAsyncContext(); + context.addListener(new AsyncListener() { + @Override + public void onComplete(AsyncEvent asyncEvent) throws IOException { + completeCounter.incrementAndGet(); + } + + @Override + public void onTimeout(AsyncEvent asyncEvent) throws IOException { + + } + + @Override + public void onError(AsyncEvent asyncEvent) throws IOException { + + } + + @Override + public void onStartAsync(AsyncEvent asyncEvent) throws IOException { + + } + }); + this.asyncRequest.onError(new AsyncEvent(new MockAsyncContext(this.request, this.response), new Exception())); + assertThat(completeCounter.get()).isOne(); + } + @Test public void setTimeoutDuringConcurrentHandling() { this.asyncRequest.startAsync();