Why does subscribe work and block doesn't in Spring reactive Mongo?

I think this might be a Spring Framework bug / usability issue.

First, let me underline the difference between subscribe and block:

  • the subscribe method kicks off the work and returns immediately. So you get no guarantee that the operation is done when other parts of your application run.
  • block is a blocking operation: it triggers the operation and waits for its completion.

For initialisation work, composing operations and calling block once is probably the best choice:

val jim: Mono<Person> =  template.save(Person("Jim"))
val john: Mono<Person> = template.save(Person("John"))
val jack: Mono<Person> = template.save(Person("Jack"))
jim.then(john).then(jack).block();

As you've stated, using block hangs the application. I suspect this might be an Spring context initialisation issue - If I remember correctly, this process might assume a single thread in some parts and using a reactive pipeline there schedules work on many threads.

Could you create a minimal sample application (using just Java/Spring Boot/Spring Data Reactive Mongo) and report that on https://jira.spring.io?


I had a similar situation where by calling "reactiveMongoTemplate.save(model).block()" the application was hanging.

The issue was caused by the @PostConstruct in one of my classes designed to create my system users after the application initialization. I think somehow It was invoked before full Spring context initialization.

@Configuration
public class InitialDataPostLoader  {
    private Logger logger = LogManager.getLogger(this.getClass());


    @PostConstruct
    public void init() {
        logger.info(String.format(MSG_SERVICE_JOB, "System Metadata initialization"));
        createDefaultUsers();
    }

By replacing @PostConstruct with ContextRefreshEvent listener the issues got resolved.

@Configuration 
public class InitialDataPostLoader implements
 ApplicationListener<ContextRefreshedEvent> {
     private Logger logger = LogManager.getLogger(this.getClass());

     @Override
     public void onApplicationEvent(ContextRefreshedEvent arg0) {

         logger.info(String.format(MSG_SERVICE_JOB, "System Metadata initialization"));
         createDefaultUsers();

     }