RFR [11] 8197564: HTTP Client implementation - JEP 321

James Roper james at lightbend.com
Wed Mar 28 02:14:41 UTC 2018


Hi Chris,

Requiring a third party adapter for using Reactive Streams for WebSockets
is not the end of the world, so I don't want to push this too hard, we can
just agree to disagree. But there were a few small questions in your reply
that I'll answer.

> Will their backpressure mechanisms map to each other easily?
>
> I see no reason that it should not. Are you aware of any?
>

It would take actually implementing an adapter to be fully aware. Note that
the Reactive Streams request() mechanism is very strictly specified,
particularly around the edge cases. As an example of just one case, what
happens if you invoke:

request(16);
request(Long.MAX_VALUE);

This is explicitly allowed by the reactive streams spec, and the expected
behavior is as as soon as demand reaches Long.MAX_VALUE, the demand is
considered to be infinite. This is also an implementation detail that many
implementations get wrong, but that's ok because the Reactive Streams TCK
verifies this behavior to ensure they get it right. But it's unspecified in
the HTTP client spec (or in the javadocs at least), so will it map nicely?
I don't know. Also, the above scenario is very possible - for example, an
implementation might consume a certain number of messages, and then decide
that it wants to ignore the rest (ignore, as opposed to push back and
block, or cancel which would close the socket), and so they just request
Long.MAX_VALUE to indicate that.

>  Will their failure handling and error handling semantics map to each
> other easily?
>
> I see no reason that they should not. In fact, most higher-level APIs
> provide more coarse grain error handling.
>

So for a start, Reactive Streams prohibits any method from throwing an
exception - for example, if you invoke request(-1), you're not allowed to
throw an IllegalArgumentException, you have to instead pass the exception
to onError.

But a lot of other methods in the WebSocket spec are allowed to throw
IOException. How a Reactive Streams implementation handles these is
unspecified, so in order to safely ensure that errors are propagated (and
the important thing here is to make sure that the right errors appear in
the right place at the right time), an adapter will have to wrap all these
methods, and implement the necessary handling to pass the errors to
onError, invoke the upstream cancel, and then ensure that after that, no
further callbacks are delegated through in either direction, and given that
this is a concurrent API with callbacks being invoked by different threads
in both directions, that's going to require things like
AtomicReference.compareAndSet, etc. Doing it correctly, ensuring there are
no race conditions, ensuring that and end developer can 100% predictably
know that all errors will be handled in a predictable way, is not at all
trivial.

-- 
*James Roper*
*Senior Octonaut*

Lightbend <https://www.lightbend.com/> – Build reactive apps!
Twitter: @jroper <https://twitter.com/jroper>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/net-dev/attachments/20180328/2e4e007a/attachment.html>


More information about the net-dev mailing list