Describe the bug Use webclient in ReactiveUserDetailsService, throw Mono.error, making ConcurrentModificationException.
If I add my custom filter and add beforeCommit, this error happen
@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class LoggingFilter implements WebFilter {
# add custom beforeCommit to ServerHttpResponse
}
2021-04-20 11:30:37.395 ERROR 69508 --- [oundedElastic-1] o.s.w.s.adapter.HttpWebHandlerAdapter : [a04758fb-1] 500 Server Error for HTTP POST "/login"
java.util.ConcurrentModificationException: null
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) ~[na:1.8.0_111]
Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Assembly trace from producer [reactor.core.publisher.FluxIterable] :
reactor.core.publisher.Flux.fromIterable(Flux.java:1134)
org.springframework.http.server.reactive.AbstractServerHttpResponse.doCommit(AbstractServerHttpResponse.java:274)
Error has been observed at the following site(s):
|_ Flux.fromIterable ⇢ at org.springframework.http.server.reactive.AbstractServerHttpResponse.doCommit(AbstractServerHttpResponse.java:274)
|_ Flux.map ⇢ at org.springframework.http.server.reactive.AbstractServerHttpResponse.doCommit(AbstractServerHttpResponse.java:274)
|_ Flux.concat ⇢ at org.springframework.http.server.reactive.AbstractServerHttpResponse.doCommit(AbstractServerHttpResponse.java:274)
|_ Flux.doOnError ⇢ at org.springframework.http.server.reactive.AbstractServerHttpResponse.doCommit(AbstractServerHttpResponse.java:275)
|_ Flux.concatWith ⇢ at org.springframework.http.server.reactive.AbstractServerHttpResponse.doCommit(AbstractServerHttpResponse.java:289)
|_ Flux.concatWith ⇢ at org.springframework.http.server.reactive.AbstractServerHttpResponse.doCommit(AbstractServerHttpResponse.java:297)
|_ Flux.then ⇢ at org.springframework.http.server.reactive.AbstractServerHttpResponse.doCommit(AbstractServerHttpResponse.java:300)
|_ Mono.doOnError ⇢ at org.springframework.http.server.reactive.AbstractServerHttpResponse.writeWith(AbstractServerHttpResponse.java:241)
|_ Mono.onErrorResume ⇢ at org.springframework.web.server.handler.ExceptionHandlingWebHandler.handle(ExceptionHandlingWebHandler.java:77)
|_ Mono.error ⇢ at org.springframework.web.server.handler.ResponseStatusExceptionHandler.handle(ResponseStatusExceptionHandler.java:67)
|_ Mono.onErrorResume ⇢ at org.springframework.web.server.handler.ExceptionHandlingWebHandler.handle(ExceptionHandlingWebHandler.java:77)
|_ Mono.doOnSuccess ⇢ at org.springframework.web.server.adapter.HttpWebHandlerAdapter.handle(HttpWebHandlerAdapter.java:249)
Stack trace:
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) ~[na:1.8.0_111]
at java.util.ArrayList$Itr.next(ArrayList.java:851) ~[na:1.8.0_111]
at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:257) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:228) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:169) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:235) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:96) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:164) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:86) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Flux.subscribe(Flux.java:8185) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxConcatArray$ConcatArraySubscriber.onComplete(FluxConcatArray.java:208) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxConcatArray.subscribe(FluxConcatArray.java:80) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Flux.subscribe(Flux.java:8185) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxConcatArray$ConcatArraySubscriber.onComplete(FluxConcatArray.java:208) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxConcatArray.subscribe(FluxConcatArray.java:80) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Mono.subscribe(Mono.java:4099) ~[reactor-core-3.4.4.jar:3.4.4]
at org.springframework.http.server.reactive.ChannelSendOperator$WriteBarrier.onNext(ChannelSendOperator.java:192) ~[spring-web-5.3.5.jar:5.3.5]
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2397) ~[reactor-core-3.4.4.jar:3.4.4]
at org.springframework.http.server.reactive.ChannelSendOperator$WriteBarrier.onSubscribe(ChannelSendOperator.java:166) ~[spring-web-5.3.5.jar:5.3.5]
at reactor.core.publisher.FluxJust.subscribe(FluxJust.java:68) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.InternalFluxOperator.subscribe(InternalFluxOperator.java:62) ~[reactor-core-3.4.4.jar:3.4.4]
at org.springframework.http.server.reactive.ChannelSendOperator.subscribe(ChannelSendOperator.java:77) ~[spring-web-5.3.5.jar:5.3.5]
at reactor.core.publisher.Mono.subscribe(Mono.java:4099) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:106) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Operators.error(Operators.java:197) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoError.subscribe(MonoError.java:52) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Mono.subscribe(Mono.java:4099) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onError(MonoPeekTerminal.java:258) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onError(MonoPeekTerminal.java:258) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondError(MonoFlatMap.java:192) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onError(MonoFlatMap.java:259) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onError(FluxContextWrite.java:121) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onError(FluxContextWrite.java:121) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:100) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondError(MonoFlatMap.java:192) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onError(MonoFlatMap.java:259) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onError(MonoPeekTerminal.java:258) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onError(MonoFlatMap.java:172) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onError(Operators.java:2062) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onError(FluxMapFuseable.java:140) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onError(FluxPeekFuseable.java:234) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onError(MonoFlatMap.java:172) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onError(Operators.java:2062) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Operators.error(Operators.java:197) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoError.subscribe(MonoError.java:52) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.Mono.subscribe(Mono.java:4099) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:81) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onComplete(FluxFilterFuseable.java:171) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.publisher.MonoPublishOn$PublishOnSubscriber.run(MonoPublishOn.java:190) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68) ~[reactor-core-3.4.4.jar:3.4.4]
at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28) ~[reactor-core-3.4.4.jar:3.4.4]
at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) ~[na:1.8.0_111]
at java.util.concurrent.FutureTask.run(FutureTask.java) ~[na:1.8.0_111]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) ~[na:1.8.0_111]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) ~[na:1.8.0_111]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_111]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_111]
at java.lang.Thread.run(Thread.java:745) ~[na:1.8.0_111]
To Reproduce
@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class LoggingFilter implements WebFilter {
# add custom beforeCommit to ServerHttpResponse
}
@Component
@AllArgsConstructor
public class UserDetailsServiceImpl implements ReactiveUserDetailsService {
private final WebClient.Builder webClientBuilder;
@Override
public Mono<UserDetails> findByUsername(String username) {
return webClientBuilder.build()
.get()
.uri("url", username)
.retrieve()
.onStatus(httpStatus -> httpStatus == HttpStatus.SERVICE_UNAVAILABLE,
clientResponse -> Mono.defer(() -> Mono.error(new InnerException(RequestResult.error()))))
.bodyToMono(RequestResult.class)
.switchIfEmpty(Mono.defer(() -> Mono.error(new InnerException(RequestResult.error()))))
.map(requestResult -> {
InnerException.ifThr(!requestResult.isSuccess(), requestResult);
return Jackson.convert(requestResult.getValue(), User.class);
});
}
}
Expected behavior It shouldn't happen.
I locating the problem, is in org.springframework.http.server.reactive.AbstractServerHttpResponse:doCommit, in this time org.springframework.web.server.session.DefaultWebSessionManager:getSession(ServerWebExchange exchange) create new session.
Sample
The environment is complicated....sorry
Comment From: jzheaux
With the information provided, I'm doubtful that this is an issue with Spring Security. Can you share why you think something in Spring Security would change to address the issue? If not, I'd recommend posting your question to StackOverflow or reporting this to Spring Framework.
Comment From: zxdposter
I now use webclient instead, so close that, thank you for answer