users@jersey.java.net

[Jersey] Re: Async client and Response.readEntity

From: Mikael Ståldal <mikael.staldal_at_appearnetworks.com>
Date: Fri, 23 Jan 2015 17:42:47 +0100

But can't you just ignore the Future return value when you use a callback?

On Fri, Jan 23, 2015 at 5:33 PM, Robert DiFalco <robert.difalco_at_gmail.com>
wrote:

> Agreed. Then you don't have to worry about the whole race condition
> problem between future.get() #readEntity and callback.complete #readEntity.
>
> On Fri, Jan 23, 2015 at 12:43 AM, 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