Ability to close connection on WebClient responses
See original GitHub issueAffects: 5.2.5.RELEASE
This feature request arises from this StackOverflow post. It could arguably fit either with spring-framework or reactor-netty, posting in spring-framework to start the discussion.
Context
Some content delivery networks recommend to re-resolve DNS on certain types of status codes (e.g. 500 internal server error). To achieve this, I’ve added a custom Netty DnsNameResolver
and DnsCache
, but I also need to close the connection, otherwise it will be released back to the pool and DNS will not be re-resolved.
Two approaches have come to light so far:
Approach 1: using Webclient alone
This was suggested by Violeta Georgieva in this answer:
return this.webClient
.get()
.uri("/500")
.retrieve()
.onStatus(status -> status.equals(HttpStatus.INTERNAL_SERVER_ERROR), clientResponse -> {
clientResponse.bodyToFlux(DataBuffer.class)
.subscribe(new BaseSubscriber<DataBuffer>() {
@Override
protected void hookOnSubscribe(Subscription subscription) {
subscription.cancel();
}
});
return Mono.error(new IllegalStateException("..."));
})
.bodyToMono(String.class);
Basically, subscribing to the response body and cancelling it immediately seems to close the connection. However, this relies on Spring’s undocumented internal behaviour and causes bodies of error responses to be lost.
Approach 2: using Reactor Netty’s TcpClient
This approach was my initial attempt, configuring the underlying TcpClient
used by WebClient
:
TcpClient tcpClient = TcpClient.create()
.observe((connection, newState) -> {
if (newState == State.RELEASED && connection instanceof HttpClientResponse) {
HttpResponseStatus status = ((HttpClientResponse) connection).status();
if (status.codeClass() != HttpStatusClass.SUCCESS) {
connection.dispose();
}
}
});
This approach also feels clunky and leads to a potential race condition: if the connection is released back to the pool after an error status code, and the observer is notified to close that connection, a new request could acquire that pooled connection in parallel.
Other approaches?
Are there any other approaches that one could implement to close the connection on error status codes? Could some more convenient interfaces be added to Spring or Reactor Netty’s APIs?
Issue Analytics
- State:
- Created 3 years ago
- Comments:9 (9 by maintainers)
Top GitHub Comments
Yes, it would mean the body is ignored.
I don’t see any good options at the WebClient level I’m afraid. We’d have to allow all the usual ways to read the body but there is no way to expose the connection at the end of that. Moreover a
Connection
abstraction over Netty, Jetty, (as well as Apache HttpClient, and JDK 11 HttpClient to come in 5.3) is unlikely to work out well. It’s not something we want to pursue. This level of control is best at the HTTP client library level.@violetagg what are your thoughts on
doAfterResponseSuccess
? As this is meant to be afterHttpClientState.RESPONSE_COMPLETED
I wonder if this here shouldn’t be in reverse order? I think the closing of the connection prevents the onComplete signal to the subscriber.Thanks a lot, great collaboration! 👍