users@jersey.java.net

[Jersey] Re: Async client and Response.readEntity

From: Robert DiFalco <robert.difalco_at_gmail.com>
Date: Thu, 29 Jan 2015 19:22:26 -0800

Mikael, my point is that code should work deterministically. A note in
javadoc that says you shouldn't do something permitted by the interface is
not my idea of good design. The interface should enforce the contract.

On Thu, Jan 29, 2015 at 7:35 AM, Mikael Ståldal <
mikael.staldal_at_appearnetworks.com> wrote:

> Just because it happens to work fine for you in this case, doesn't mean
> it's a good idea to do it in general.
>
> On Thu, Jan 29, 2015 at 4:24 PM, Robert DiFalco <robert.difalco_at_gmail.com>
> wrote:
>
>> No because if the Callback and Future are parameterized on the entity
>> type rather than Response it works fine. I think a simpler solution would
>> be to wrap the callback such that when completed or error completes it sets
>> the Future value and unblocks #get. That way you can at least make
>> assurances that #get does not unblocked until the Callback has completed.
>>
>> On Thu, Jan 29, 2015 at 12:05 AM, Mikael Ståldal <
>> mikael.staldal_at_appearnetworks.com> wrote:
>>
>>> 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
>>>
>>
>>
>
>
> --
> Mikael Ståldal
> Chief Software Architect
> *Appear*
> Phone: +46 8 545 91 572
> Email: mikael.staldal_at_appearnetworks.com
>