-
Notifications
You must be signed in to change notification settings - Fork 38.5k
Guard against ConcurrentModificationException
when the response processes commitActions
#27587
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
If it is a framework problem, we could try using a different primitive instead of |
I realize the above snippet is just a way to cause the error, but I do wonder if the root cause is a race condition where the For the former, we should arguably reject a concurrent registration, in the call to For the latter, i think there is a case to allow it, but it'd be useful to confirm that's what happens. I've looked at Spring Security header writers and don't see anything trying to use the |
ConcurrentModificationException
in WebFlux when the response processes commitActions
Spring Security does not register any |
Unfortunately not possible to determine the root cause. I think the best we can do is to reject further commitActions from being added when the response is already committed, or ignore them, e.g. by using Generally, if all request handling is composed in one reactive chain, response writing should happen at the end, and there shouldn't be any competition. The fact that there is implies that there is either a component that executes asynchronously without being composed into the request handling chain (e.g. started with an explicit call to |
ConcurrentModificationException
in WebFlux when the response processes commitActions
ConcurrentModificationException
when the response processes commitActions
On closer look, the above test with the nested |
Affects: <Spring Framework version>v5.3.8
spring-web
v5.3.8org.springframework.http.server.reactive.AbstractServerHttpResponse
protected Mono<Void> doCommit(@Nullable Supplier<? extends Mono<Void>> writeAction) {
Hello,
Sometimes there is a race condition between
beforeCommit
statements for the same request.This error only arises during traffic peaks
Both
HttpHeaderWriterWebFilter
andDefaultWebSessionManager
addcommitActions
to the responsehttps://github.com/spring-projects/spring-security-reactive/blob/37749a64f782c2b2f81afb3db1b30cea3e956839/spring-security-reactive/src/main/java/org/springframework/security/web/server/header/HttpHeaderWriterWebFilter.java#L42
spring-framework/spring-web/src/main/java/org/springframework/web/server/session/DefaultWebSessionManager.java
Line 88 in b595dc1
But sometimes (fortunately it is not happening a lot)
DefaultWebSessionManager
adds its commitAction after the methoddoCommit
has started.As a result,
doCommit
doesFlux.concat(Flux.fromIterable(this.commitActions).map(Supplier::get))
, which immediately stores an iterator over commitActions.spring-framework/spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpResponse.java
Line 243 in 9c33d27
Then
DefaultWebSessionManager
adds its commitAction,which means that this.commitActions has size 2, but the iterator was built for a list of 1.
When the FluxIterable subscribes, it does iterator.next, which invokes
ArrayList$Itr.checkForComodification
This is where I get the
ConcurrentModificationException
.To illustrate the problem, I am providing you this test class in kotlin.
This test systematically fails, but there is no race condition, it is simply a beforeCommit that takes place during another one, making the code build an iterator on a list of 1 when the list size increases to 2.
If it is an app-level error, can we think of a better error handling to avoid such problems ?
Otherwise, if it is a framework-level error, I would be happy to contribute, just let me know.
The text was updated successfully, but these errors were encountered: