Skip to content

Ensure AsyncListener#onError does not return until dispatch completes #34192

@rstoyanchev

Description

@rstoyanchev

When a controller returns Flux<ServerSentEvent>, SseEmitter is used to write events. If the connection drops, the write fails with IOException in a Spring MVC TaskExecutor thread while in parallel we also get a Servlet container AsyncListener#onError callback.

In #32340, WebAsyncManager was enhanced to be protected in this race, so only one thread can dispatch. However, it is also crucial to ensure the onError callback holds up until the dispatch completes regardless of who wins. WebAsyncManager#setConcurrentResultAndDispatch guarantees this through synchronization, but when using DeferredResult, the onError callback may not call that method at all if DeferredResult error handling finds the result is already set by the competing thread. As a result, the onError callback may exit the container thread before dispatch in the Spring MVC thread compltes, which leads to the stacktrace in #33421 (comment) and also in #34188.

The issue does not apply when using Callable, e.g. via StreamingResponseBody as in that case setConcurrentResultAndDispatch is always called.

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)status: backportedAn issue that has been backported to maintenance branchestype: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions