Deadlock when initializing bean in BeanPostProcessor in Spring Boot 3.3.0 #32904
Labels
in: core
Issues in core modules (aop, beans, core, context, expression)
status: invalid
An issue that we don't feel is valid
Background
I'm developing an event-sourcing library/framework called Occurrent that uses Spring/Boot in some of its modules. I'm now trying to add annotation support for subscriptions by leveraging the Spring eco-system. For example:
You can also specify a past time when streaming of events should occur, for example:
This will stream all events from the beginning of time and then continue subscribing to new ones as they come, and in this example, we've also specified
waitUntilStarted=TRUE
which means that all historic events should be streamed before the Spring Boot application starts serving requests.And here lies the problem. I've implemented support for the annotation by using a
BeanPostProcessor
, you can find the implementation in org.occurrent.springboot.mongo.blocking.OccurrentAnnotationBeanPostProcessor. When the code detects thatwaitUntilStarted
istrue
(see line 179), it calls the code that starts streaming old events. The code of interest starts inSpringMongoEventStore
at line 373 which performs this query:Now, deep down in Spring Boot in
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
, at line 214 (spring-beans-6.1.6-sources.jar!/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java:214), in thepublic Object getSingleton(String beanName, ObjectFactory<?> singletonFactory)
method there's a synchronized block:And here my application is stuck forever. This happens when
getSingleton
is called for a bean named "springApplicationAdminRegistrar".I get the same problem with Spring Boot 3.2.5, 3.2.6, and 3.3.0.
Reproduce
You can reproduce this by cloning the Occurrent repository (
git clone [email protected]:johanhaleby/occurrent.git
), checking out theissue/spring-boot-deadlock
branch, and then running the main method inorg.occurrent.example.domain.numberguessinggame.mongodb.spring.blocking.Bootstrap
from e.g. Intellij. Note you need to start MongoDB locally before you run the class. What will then happen is that the following log will be printed:And then the application hangs in the synchronized block mentioned above. If everything was working, you should have been able to navigate to
http://localhost:8080/games
.While creating this issue I wanted to make it easier to reproduce, so I created a
TestBoostrap
( in packageorg.occurrent.example.domain.numberguessinggame.mongodb.spring.blocking
) that uses test containers to boot the application so that you don't need to start MongoDB externally. But the strange thing is that if I run the main method fromTestBootstrap
, the deadlock doesn't occur and you can navigate tohttp://localhost:8080/games
. Could it be a timing issue? If so, it's very deterministic.Am I doing something wrong or could this be a potential bug?
The text was updated successfully, but these errors were encountered: