Bug Report
Versions
- Driver: 1.0.0.RELEASE
- Database: postgres:13
- Java: liberica-17.0.6
- OS: Windows 10 Pro 22H2
Current Behavior
After the reactive repository (R2dbcRepository), operators are executed in one thread (reactor-tcp-nio-1) out of 10 available
Table schema
CREATE TABLE value (
id bigint NOT NULL GENERATED ALWAYS AS IDENTITY,
value varchar null
)
Input Code
package com.example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class R2DBCApplication {
private static final Logger log = LoggerFactory.getLogger(R2DBCApplication.class);
public static void main(final String[] args) {
SpringApplication.run(R2DBCApplication.class, args);
}
}
package com.example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import java.util.UUID;
@RestController
public class ValueController {
private static final Logger log = LoggerFactory.getLogger(ValueController.class);
@Autowired
private ValueRepository repository;
@GetMapping("/value")
public Mono<String> get() {
final var uuid = UUID.randomUUID().toString();
log.info("start for uuid = {}", uuid);
return repository
.findById(1L)
.map(ValueEntity::getId)
.map(String::valueOf)
.switchIfEmpty(Mono.fromSupplier(() -> uuid))
.doOnNext(v -> log.info("after switchIfEmpty uuid = {}", v))
.doOnNext(v -> log.info("breakpoint uuid = {}", v));
}
}
package com.example;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
@Table("value")
public class ValueEntity {
@Id
@Column("id")
private Long id;
@Column("value")
private String value;
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(final String value) {
this.value = value;
}
}
package com.example;
import org.springframework.data.r2dbc.repository.R2dbcRepository;
public interface ValueRepository extends R2dbcRepository<ValueEntity, Long> {
}
server.port: 9080
spring:
application.name: r2dbc-service
r2dbc:
url: r2dbc:postgresql://localhost:5433/postgres
username: postgres
password: 12345
properties:
schema: public
logging.level.root: DEBUG
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>r2dbc-postgresql</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Steps to reproduce
- set breakpoint in ValueController on lambda (not line) in .doOnNext(v -> log.info("breakpoint uuid = {}", v))
- open url http://localhost:9080/value in browser
- open url http://localhost:9080/value in browser
result: breakpoint won't hit a second time (reactor-tcp-nio-1 stopped, second connection wait while reactor-tcp-nio-1 release)
Expected behavior
After the reactive repository (R2dbcRepository), operators are executed in separated threads (thread per connection)
Comment From: philwebb
I suspect that your breakpoint is stopping on the ValueController.get() method rather than the doOnNext callback in which case I'd expect the behavior you're describing.
Regardless, Spring Boot does little more than configure the stack so if you do think this is a bug you'll either have to raise it at https://github.com/spring-projects/spring-framework or https://github.com/spring-projects/spring-data-r2dbc.
If you do open another issue, please attach your sample application as a zip file. This is easier for us to run than copying snippets from the issue.