Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When I upgrade the version of spring-boot-starter-webflux from 3.2.2 to 3.2.6, there is a problem with retryWhen() and block() #33567

Closed
YChen9511 opened this issue Sep 19, 2024 · 7 comments
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: invalid An issue that we don't feel is valid

Comments

@YChen9511
Copy link

Hello team,
I find that when I upgrade the version of spring-boot-starter-webflux from 3.2.2 to 3.2.6, there is a problem with retryWhen() and block().
Below is my code:

@RestController
public class TestController {
    private final Service service;

    public TestController(Service service) {
        this.service = service;
    }

    @GetMapping("/test")
    public Object testController(){
        return service.getDate("/non-existent-path", String.class).single().block();
    }
}
@org.springframework.stereotype.Service
@Slf4j
public class Service {
    WebClient client = WebClient.create("http://localhost:8080");

    public <T> Flux<T> getDate(String uri, Class<T> clazz){
        return client.get().uri(uri).retrieve().bodyToFlux(clazz)
                .retryWhen(Retry.backoff(3, Duration.ofMillis(2)).doBeforeRetry(
                        i->log.info(String.valueOf(i.totalRetriesInARow()), i.totalRetries())));
    }
}
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
            <version>3.2.6</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>

</dependencies>

Here is the specific phenomenon:
When I use webclient to call a non-existent uri and an 404 error occurs, block() and retryWhen() will asynchronously capture the error signal, causing my controller to return immediately. At the same time, there is an asynchronous thread executing the retry logic.

Before the retry logic is completed, block() captures the error signal.

What I expect is block() catches the error signal and then return after my retry logic is executed, just as version 3.2.2.
There's no such problem when i use version 3.2.2.

Looking forward to your reply. Thank u!

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Sep 19, 2024
@snicoll snicoll transferred this issue from spring-projects/spring-boot Sep 19, 2024
@YChen9511
Copy link
Author

I think it is related to netty web server. If I add spring-boot-starter-web (version 3.2.6) and switch the web server from netty to tomcat, there is no such problem.

@bclozel
Copy link
Member

bclozel commented Sep 19, 2024

This is most likely linked to the Spring Framework version or the Reactor version.

Can you try with your sample application with Spring Boot 3.2.2 and test with:

  1. overriding reactor with ext["reactor-bom.version"]="2023.0.6" (instead of 2023.0.2)
  2. overriding spring framework with ext["spring-framework.version"]="6.1.8" (instead of 6.1.3)

Doing so should point in the right direction.

@bclozel bclozel added the status: waiting-for-feedback We need additional information before we can continue label Sep 19, 2024
@YChen9511
Copy link
Author

YChen9511 commented Sep 19, 2024

This is most likely linked to the Spring Framework version or the Reactor version.

Can you try with your sample application with Spring Boot 3.2.2 and test with:

  1. overriding reactor with ext["reactor-bom.version"]="2023.0.6" (instead of 2023.0.2)
  2. overriding spring framework with ext["spring-framework.version"]="6.1.8" (instead of 6.1.3)

Doing so should point in the right direction.

When i overrode the versions as you said, the problem did not recur.
Here is my build.gradle:

ext{
    springFrameworkVersion = '6.1.8'
    reactorBomVersion = '2023.0.6'
}

dependencies {

    implementation 'org.springframework.boot:spring-boot-starter-webflux:3.2.2'
    implementation 'org.springframework:spring-core:${springFrameworkVersion}'
    implementation 'org.springframework:spring-context:${springFrameworkVersion}'
    implementation 'org.springframework:spring-web:${springFrameworkVersion}'
    implementation 'org.springframework:spring-beans:${springFrameworkVersion}'
    // import BOM
    implementation platform('io.projectreactor:reactor-bom:${reactorBomVersion}')

    // add dependencies without a version number
    implementation 'io.projectreactor:reactor-core'
}

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 19, 2024
@bclozel
Copy link
Member

bclozel commented Sep 19, 2024

My question was about overriding just one, then the other. This will tell us where the issue is.

@bclozel bclozel added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Sep 19, 2024
@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 19, 2024
@bclozel
Copy link
Member

bclozel commented Sep 19, 2024

Sorry it's me - I didn't get that you didn't reproduce the problem with both overrides. It seems that dependency management is getting in the way here and it might be possible that your tests were not conclusive. Can you share a minimal sample application that reproduces the problem with Spring Boot 3.2.6 (ideally created with start.spring.io) and we'll take it from there?

@bclozel bclozel added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Sep 19, 2024
@YChen9511
Copy link
Author

Sorry it's me - I didn't get that you didn't reproduce the problem with both overrides. It seems that dependency management is getting in the way here and it might be possible that your tests were not conclusive. Can you share a minimal sample application that reproduces the problem with Spring Boot 3.2.6 (ideally created with start.spring.io) and we'll take it from there?

sure.
The attachment is a minimal sample application. I created it with start.spring.io.
demo.zip

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 19, 2024
@bclozel
Copy link
Member

bclozel commented Sep 20, 2024

Thanks for the sample application.
I'm not sure about the change of behavior and I couldn't track so far what changes here. I suspect that an unrelated change is uncovering a root problem in your application: you should not call block within a non-blocking thread and this can lead to unexpected results and racing issues, such like this.

With Spring Boot 3.2.3+, I'm getting the following exception:

java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2
	at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:86) ~[reactor-core-3.6.3.jar:3.6.3]
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	*__checkpoint ⇢ HTTP GET "/test" [ExceptionHandlingWebHandler]
Original Stack Trace:
		at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:86) ~[reactor-core-3.6.3.jar:3.6.3]
		at reactor.core.publisher.Mono.block(Mono.java:1779) ~[reactor-core-3.6.3.jar:3.6.3]
		at com.example.demo.TestController.testController(TestController.java:18) ~[main/:na]

I'm closing this issue as invalid.

@bclozel bclozel closed this as not planned Won't fix, can't repro, duplicate, stale Sep 20, 2024
@bclozel bclozel added in: web Issues in web modules (web, webmvc, webflux, websocket) status: invalid An issue that we don't feel is valid and removed status: waiting-for-triage An issue we've not yet triaged or decided on status: feedback-provided Feedback has been provided labels Sep 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

3 participants