users@jersey.java.net

[Jersey] Re: Async client and Response.readEntity

From: Mikael Ståldal <mikael.staldal_at_appearnetworks.com>
Date: Thu, 29 Jan 2015 09:05:28 +0100

Then I guess that you should never use the get() method on the returned
Future when you use a callback. Perhaps the documentation should mention
this.

On Wed, Jan 28, 2015 at 6:37 PM, Marek Potociar <marek.potociar_at_oracle.com>
wrote:

> 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>
> 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> 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> wrote:
>>>
>>>> Hi Mikael,
>>>>
>>>> Please see inline.
>>>>
>>>> On 12 Jan 2015, at 11:29, Mikael Ståldal <
>>>> 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
>>>>
>>>>
>>>> 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).
>>>>
>>>>
>>>> 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 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> 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> 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
>>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>> --
>>>> Mikael Ståldal
>>>> Chief Software Architect
>>>> *Appear*
>>>> Phone: +46 8 545 91 572
>>>> Email: mikael.staldal_at_appearnetworks.com
>>>>
>>>>
>>>>
>>>
>>>
>>> --
>>> Mikael Ståldal
>>> Chief Software Architect
>>> *Appear*
>>> Phone: +46 8 545 91 572
>>> Email: mikael.staldal_at_appearnetworks.com
>>>
>>
>>
>
>
> --
> Mikael Ståldal
> Chief Software Architect
> *Appear*
> Phone: +46 8 545 91 572
> Email: mikael.staldal_at_appearnetworks.com
>
>
>


-- 
Mikael Ståldal
Chief Software Architect
*Appear*
Phone: +46 8 545 91 572
Email: mikael.staldal_at_appearnetworks.com