quarkus: Exceptions thrown in Rest client should be more specific
Description
Currently when using the Quarkus rest client (regular & reactive), any response other than a 2xx is thrown as a javax.ws.rs.WebApplicationException
(or a RESTEasy subclass of it). In Quarkus using RESTEasy Reactive, the exception is a org.jboss.resteasy.reactive.ClientWebApplicationException
, which is a subclass of javax.ws.rs.WebApplicationException
. JAX-RS exposes more fine-grained exceptions for lots of http statuses.
Because of this, using fault tolerance handling is very difficult, as you aren’t able to use the built-in skipOn
fields in the fault tolerance annotations.
Say I want to ignore a circuit breaker/fallback/retry on a specific http status? I can’t use the fault tolerance exception because everything is always a javax.ws.rs.WebApplicationException
.
As an example, say I want to ignore a circuit breaker if a client call returns a 404. I have to implement some custom logic:
HeroRestClient.java:
@Path("/api/heroes")
@Produces(MediaType.APPLICATION_JSON)
@RegisterRestClient(configKey = "hero-client")
interface HeroRestClient {
@GET
@Path("/random")
Uni<Hero> findRandomHero();
}
HeroClient.java:
@ApplicationScoped
public class HeroClient {
private final HeroRestClient heroClient;
public HeroClient(@RestClient HeroRestClient heroClient) {
this.heroClient = heroClient;
}
@CircuitBreaker(requestVolumeThreshold = 8, failureRatio = 0.5, delay = 2, delayUnit = ChronoUnit.SECONDS)
@CircuitBreakerName("findRandomHero")
CompletionStage<Hero> getRandomHero() {
// Want the 404 handling to be part of the circuit breaker
// This means that the 404 responses aren't considered errors by the circuit breaker
return this.heroClient.findRandomHero()
.onFailure(throwable ->
Optional.ofNullable(throwable)
.filter(t -> t instanceof WebApplicationException)
.map(WebApplicationException.class::cast)
.map(WebApplicationException::getResponse)
.filter(response -> response.getStatus() == Status.NOT_FOUND.getStatusCode())
.isPresent()
).recoverWithNull()
.subscribeAsCompletionStage();
}
}
When the JAX-RS spec already has exceptions that map to most of the known http status codes. If that was the case, then my custom code could be completely replaced with something like
@Path("/api/heroes")
@Produces(MediaType.APPLICATION_JSON)
@RegisterRestClient(configKey = "hero-client")
interface HeroRestClient {
@GET
@Path("/random")
@CircuitBreaker(
requestVolumeThreshold = 8,
failureRatio = 0.5,
delay = 2,
delayUnit = ChronoUnit.SECONDS,
skipOn = NotFoundException.class
)
@CircuitBreakerName("findRandomHero")
Uni<Hero> findRandomHero();
}
See https://github.com/smallrye/smallrye-fault-tolerance/issues/524#issuecomment-1061891842 for some conversation around this as well.
Implementation ideas
No response
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 6
- Comments: 22 (20 by maintainers)
Adding my +1
I think its because in
org.jboss.resteasy.reactive.client.impl.RestClientRequestContext
there isSeems I’d have to invent my own
Exception
subclass rather than re-use one of the existing JAX-RS ones, since they all extend fromWebApplicationException
. The resteasy reactive client will always wrap anyWebApplicationException
in aorg.jboss.resteasy.reactive.client.impl.ClientWebApplicationException
. This seems inefficient to me, since the exception classes that map to http status codes are already there. Why should I have to invent my own?UPDATE: I verified this is the case. This works if I create my own exception class rather than re-use one of the default ones, which isn’t something I really want to do.