users@jersey.java.net

[Jersey] Re: Async client and Response.readEntity

From: Marek Potociar <marek.potociar_at_oracle.com>
Date: Wed, 28 Jan 2015 18:37:52 +0100

The reason for that is that you should be able to cancel the running task. There is nothing strange really - look at Executor APIs in Java.

Marek

> On 23 Jan 2015, at 09:43, Mikael Ståldal <mikael.staldal_at_appearnetworks.com> wrote:
>
> To me i seems strange that the same API method both takes a callback and returns a Furure. It should be either or, not both.
>
> On Thu, Jan 22, 2015 at 7:48 PM, Robert DiFalco <robert.difalco_at_gmail.com <mailto:robert.difalco_at_gmail.com>> wrote:
> Marek, the issue I had is that the behavior of getting a Future<Response> with a callback is indeterminate. There seems to be a race condition with readEntity such that even if you request the entity to be buffered it can still end up as malformed in either the Future#get or the InvocationCallback#completed.
>
> On Thu, Jan 22, 2015 at 9:34 AM, Mikael Ståldal <mikael.staldal_at_appearnetworks.com <mailto:mikael.staldal_at_appearnetworks.com>> wrote:
> > 1. InvocationCallback<Order> is run from some other thread (i.e. asynchronously) that has issued the request
>
> Yes, so far so good. But then I cannot access the response metadata (HTTP status, response headers).
>
> > 2. The callback is only invoked AFTER the Response.readEntity(Order.class) has completed. So having an InvocationCallback<Response> and invoking Response.readEntity(..) inside is not making things worse.
>
> So if I do like this:
>
> Invocation invocation = client.target(someURL).request().buildGet();
> invocation.submit(new InvocationCallback<Response> {
> public void completed(Response response) {
> int statusCode = response.getStatus();
> Order order = response.readEntity(Order.class); // blocking?
> process(statusCode, order);
> }
> public void failed(Throwable throwable) {
> error();
> }
> });
>
> It will not block on I/O when invoking response.readEntity(Order.class)?
> If so, my understanding of how it works was wrong, and the issue is invalid.
>
> > Perhaps you are looking for a non-blocking I/O API support
>
> I am, but this particular issue is not really about that.
>
> > Something like Response.readEntity(Order.class, order -> { … }) ?
>
> If it works the way you say (Response.readEntity is non-blocking since it just return something which has already been read, parsed and buffered in memory), that shouldn't be necessary.
>
> > Btw. do you know that you can easily check the response code from a JAX-RS ClientResponseFilter <https://jax-rs-spec.java.net/nonav/2.0-rev-a/apidocs/javax/ws/rs/client/ClientResponseFilter.html> ?
>
> To me, it seems quite clumsy if I would have to use a filter in this use case.
>
>
> On Thu, Jan 22, 2015 at 1:42 PM, Marek Potociar <marek.potociar_at_oracle.com <mailto:marek.potociar_at_oracle.com>> wrote:
> Hi Mikael,
>
> Please see inline.
>
>> On 12 Jan 2015, at 11:29, Mikael Ståldal <mikael.staldal_at_appearnetworks.com <mailto:mikael.staldal_at_appearnetworks.com>> wrote:
>>
>> No, I did not get any answer to this. And neither to the JIRA issues I have filed:
>>
>> https://java.net/jira/browse/JERSEY-2682 <https://java.net/jira/browse/JERSEY-2682>
> C&Ping my comment from the issue:
>
> I have looked at the issue and I’m not sure I understand the problem you are pointing out:
>
> 1. InvocationCallback<Order> is run from some other thread (i.e. asynchronously) that has issued the request
> 2. The callback is only invoked AFTER the Response.readEntity(Order.class) has completed. So having an InvocationCallback<Response> and invoking Response.readEntity(..) inside is not making things worse.
>
> Perhaps you are looking for a non-blocking I/O API support, which is planned for the next release of JAX-RS <https://jcp.org/en/jsr/detail?id=370>? Something like Response.readEntity(Order.class, order -> { … }) ?
> Btw. do you know that you can easily check the response code from a JAX-RS ClientResponseFilter <https://jax-rs-spec.java.net/nonav/2.0-rev-a/apidocs/javax/ws/rs/client/ClientResponseFilter.html> ?
>
>>
>> To me, it seems like the async part of the JAX-RS 2.0 client API is flawed (not to mention the default implementation in Jeresy: https://java.net/jira/browse/JERSEY-2058 <https://java.net/jira/browse/JERSEY-2058>).
>
> The primary problem is in lack of NIO support in the current JAX-RS API. We’re looking into fixing it for the next JAX-RS release, as noted above. Obviously, we will first try to make it work in Jersey, so Jersey users should have a working solution long before JAX-RS.next is released. I do not have any ETA at this point though.
>
>>
>> It's a pity, since the synchronous client API in JAX-RS 2.0 (and its implementation in Jersey) is really nice.
>>
>> I am considering using something else for async REST client, such as https://github.com/AsyncHttpClient/async-http-client <https://github.com/AsyncHttpClient/async-http-client> or Jetty client.
>
> FWIW, our grizzly connector is actually wrapped into async HTTP client API. But again, current lack of NIO support in JAX-RS APIs is making it difficult to come up with a good async client solution. That said, we’re already trying, stay tuned.
>
> Marek
>
>>
>> On Wed, Dec 31, 2014 at 9:06 PM, Robert DiFalco <robert.difalco_at_gmail.com <mailto:robert.difalco_at_gmail.com>> wrote:
>> Did you ever get an answer to this?
>>
>> On Mon, Oct 6, 2014 at 7:45 AM, Mikael Ståldal <mikael.staldal_at_appearnetworks.com <mailto:mikael.staldal_at_appearnetworks.com>> wrote:
>> Consider using Jersey client in async mode with an InvocationCallback<Response>, and then use readEntity() on the Response. Order is a custom domain object for which we have a MessageBodyReader available.
>>
>> Invocation invocation = client.target(someURL).request().buildGet();
>> invocation.submit(new InvocationCallback<Response> {
>> public void completed(Response response) {
>> int status = response.getStatus();
>> if (status == 200) {
>> Order order = response.readEntity(Order.class); // blocking ?
>> process(order);
>> } else {
>> error();
>> }
>> }
>> public void failed(Throwable throwable) {
>> error();
>> }
>> });
>>
>> Is the response.readEntity() call blocking? Is it I/O bound if the response is large? Or is the whole response read from network before the completed() callback is invoked?
>>
>> Will the asynchronicity be improved if I do InvocationCallback<Order> instead? What if I want to get other information from the Response?
>>
>> --
>> Mikael Ståldal
>> Chief Software Architect
>> Appear
>> Phone: +46 8 545 91 572 <>
>> Email: mikael.staldal_at_appearnetworks.com <mailto:mikael.staldal_at_appearnetworks.com>
>>
>>
>>
>> --
>> Mikael Ståldal
>> Chief Software Architect
>> Appear
>> Phone: +46 8 545 91 572 <>
>> Email: mikael.staldal_at_appearnetworks.com <mailto:mikael.staldal_at_appearnetworks.com>
>
>
>
> --
> Mikael Ståldal
> Chief Software Architect
> Appear
> Phone: +46 8 545 91 572 <>
> Email: mikael.staldal_at_appearnetworks.com <mailto:mikael.staldal_at_appearnetworks.com>
>
>
>
> --
> Mikael Ståldal
> Chief Software Architect
> Appear
> Phone: +46 8 545 91 572 <>
> Email: mikael.staldal_at_appearnetworks.com <mailto:mikael.staldal_at_appearnetworks.com>