Skip to content

Commit bdccd90

Browse files
committed
Fix AsyncContext to be completed on AsyncListener.onError()
Closes gh-31541
1 parent 534d322 commit bdccd90

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

spring-web/src/main/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ public void onTimeout(AsyncEvent event) throws IOException {
151151

152152
@Override
153153
public void onError(AsyncEvent event) throws IOException {
154+
if (this.asyncContext != null) {
155+
this.asyncContext.complete();
156+
}
154157
this.exceptionHandlers.forEach(consumer -> consumer.accept(event.getThrowable()));
155158
}
156159

spring-web/src/test/java/org/springframework/web/context/request/async/StandardServletAsyncWebRequestTests.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616

1717
package org.springframework.web.context.request.async;
1818

19+
import java.io.IOException;
20+
import java.util.concurrent.atomic.AtomicInteger;
1921
import java.util.function.Consumer;
2022

2123
import jakarta.servlet.AsyncEvent;
24+
import jakarta.servlet.AsyncListener;
2225
import org.junit.jupiter.api.BeforeEach;
2326
import org.junit.jupiter.api.Test;
2427

@@ -124,6 +127,36 @@ public void onErrorHandler() throws Exception {
124127
verify(errorHandler).accept(e);
125128
}
126129

130+
@Test
131+
public void onErrorShouldCompleteAsyncContext() throws Exception {
132+
this.asyncRequest.startAsync();
133+
AtomicInteger completeCounter = new AtomicInteger();
134+
MockAsyncContext context = (MockAsyncContext) this.request.getAsyncContext();
135+
context.addListener(new AsyncListener() {
136+
@Override
137+
public void onComplete(AsyncEvent asyncEvent) throws IOException {
138+
completeCounter.incrementAndGet();
139+
}
140+
141+
@Override
142+
public void onTimeout(AsyncEvent asyncEvent) throws IOException {
143+
144+
}
145+
146+
@Override
147+
public void onError(AsyncEvent asyncEvent) throws IOException {
148+
149+
}
150+
151+
@Override
152+
public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
153+
154+
}
155+
});
156+
this.asyncRequest.onError(new AsyncEvent(new MockAsyncContext(this.request, this.response), new Exception()));
157+
assertThat(completeCounter.get()).isOne();
158+
}
159+
127160
@Test
128161
public void setTimeoutDuringConcurrentHandling() {
129162
this.asyncRequest.startAsync();

0 commit comments

Comments
 (0)