How to call Spring MongoRepository from an ExecutorService
The problem
Recently I encountered an issue in code when I tried to call the Spring MongoRepository from a non-Spring-managed thread in a Java Spring Boot application. Here is a brief description of the issue.
The Repository interface
public interface ResponseRepository extends MongoRepository<Response, String> {
}
It’s a standard Spring Repository interface without any custom methods.
The calling class
@Component //A Spring Component
public class AnImaginaryComponent {
@Autowired
private ResponseRepository responseRepo;
public void saveResponseInANewThread(Response r) {
//Create an Executor service
ExecutorService executor = Executors.newSingleThreadExecutor();
//Submit a Runnable instance
executor.submit(() -> responseRepo.save(r));
}
}
When anImaginaryComponent.saveResponseInANewThread(r)
is invoked, it
never saves the r Response
into the database. And the worst part is that
it doesn’t throw any exceptions or print any log messages for the failure.
The solution
Rewrite the ResponseRepository
interface as below:
import org.springframework.scheduling.annotation.Async;
public interface ResponseRepository extends MongoRepository<Response, String> {
@Async
<S extends Response> S save(S entity);
}
And enable sync.
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class MySuperImportantSpringBootApplication {
Apparently the @Async annotation tells Spring to execute the annotated methods asynchronously and not to wait for the main thread.
It was not easy to find the workaround as there were very few resources on the internet on this issue (which is why I decided to post it on my blog) but this StackOverflow post did help.