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

Multipart timeouts when send via WebClient after setting R/W timeouts via doOnConnected/HttpClient/ReactorClientHttpConnector #23375

Closed
zacharo opened this issue Jul 27, 2019 · 3 comments
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket)

Comments

@zacharo
Copy link

zacharo commented Jul 27, 2019

Affects: SpringBoot 2.1.6.RELEASE


Usecase
Want to proxy a Multipart content in reactive manner from server to another server (eg. curl/postman call -> serverApp1 -> serverApp2).

Problem
The the whole chain hangs and timeouts when reaching server2. All Reactive Filters on the way on both servers are called properly, proper endpoint on server2 is determined, but the actual controller method of server2 never gets called. After the set timeout, the connection is cancelled.

Suspected cause
Setting the timeouts on the WebClient (see commented section of code below).

Notes

  • The the example of broken code is below, to fix it, comment out the 'doOnConnected' section -> the whole flow finishes successfully
  • The problem seems to be related only when multipart content is involved, 'basic' JSON-API calls seem to work fine
  • The approach how to configure is similar as recommened in Java config bean definitions are overridden by superclass (SPR-10992) #390

Code (prototype of the error extracted from the actual app, stripped of filters, security, etc):

@RestController
class Multipart {

    @PostMapping("/multipartA")
    fun endpointA(
            @RequestPart("file") file: FilePart
    ): Mono<Unit> = client.post()
            .uri("localhost:8080/multipartB")
            .syncBody(
                    MultipartBodyBuilder().also { builder ->
                        builder.asyncPart("file", file.content(), DataBuffer::class.java).headers {
                            it.addAll(file.headers())
                        }
                        builder.asyncPart("some", SomJsonDTO("xx").toMono(), SomJsonDTO::class.java)
                    }.build()
            ).exchange()
            .map {
                if (!it.statusCode().is2xxSuccessful)
                    throw IllegalStateException("Invalid response: ${it.statusCode()}")
            }

    @PostMapping("/multipartB")
    fun endpointB(
            @RequestPart("file") file: FilePart,
            @RequestPart("some") some: SomJsonDTO,
            serverWebExchange: ServerWebExchange
    ): Mono<Unit> {
        println("Received the request: $some")
        return file.transferTo(File("/home/some-user/stuff/result.png")).map {
            Unit
        }
    }


    companion object {
        val client = HttpClient.create().tcpConfiguration { client ->
            with(client) {
                option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 300000)
                // *** commenting out the 'doOnConnected' fixes the issue ***
                doOnConnected { conn ->
                    conn.addHandlerLast(ReadTimeoutHandler(30))
                    conn.addHandlerLast(WriteTimeoutHandler(30))
                }
                // ***
            }
        }.compress(true).let {
            WebClient.builder()
                    .clientConnector(ReactorClientHttpConnector(it))
                    .build()
        }
    }

}

data class SomJsonDTO(val x: String)
`

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jul 27, 2019
@rstoyanchev rstoyanchev added the in: web Issues in web modules (web, webmvc, webflux, websocket) label Nov 8, 2021
@snicoll
Copy link
Member

snicoll commented Nov 2, 2023

@zacharo sorry for the delay. Can you please move this code in text into an actual sample that we can run, ideally using Java only. You can share that with us by attaching a zip to this issue or by pushing the code to a separate GitHub repository.

@snicoll snicoll added the status: waiting-for-feedback We need additional information before we can continue label Nov 2, 2023
@spring-projects-issues
Copy link
Collaborator

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

@spring-projects-issues spring-projects-issues added the status: feedback-reminder We've sent a reminder that we need additional information before we can continue label Nov 9, 2023
@spring-projects-issues
Copy link
Collaborator

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.

@spring-projects-issues spring-projects-issues closed this as not planned Won't fix, can't repro, duplicate, stale Nov 16, 2023
@spring-projects-issues spring-projects-issues removed status: waiting-for-feedback We need additional information before we can continue status: feedback-reminder We've sent a reminder that we need additional information before we can continue status: waiting-for-triage An issue we've not yet triaged or decided on labels Nov 16, 2023
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)
Projects
None yet
Development

No branches or pull requests

4 participants