-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IncrementalCallback support #9
Comments
…onses; decouple from error handling
…onses; decouple from error handling
Current thinking about how to invoke the asynchronous calls.
Rationale. It is true that calls such as |
Thinking about this a bit further. I could see how providing for Observer methods on alternate threads could lead to safer systems. As a runtime, I'd probably prefer the ability to control this behavior, as I could isolate the threads used per-app easier. A nice compromise would be the same approach retrofit uses, which is to default to a synchronous executor, which just calls run. |
I need to clean up my impl, but the following works "on my laptop"TM
with the decoder as follows
stitched in similar to below:
I'll have a similar decoder for SAX (which is meh, I know, but I'm fine with it :) ) |
note research for integration with netty or otherwise chunkers is not complete, yet. This may impact the design of |
Makes sense for the reasons you gave.
This is also being discussed at: ReactiveX/RxJava#296 I'd be interested in your feedback there. |
thx for your feedback.. and returned some on the rx thread. |
latest commits work as expected: https://github.com/Netflix/feign/blob/observer/feign-core/src/test/java/feign/examples/GitHubExample.java something that may surprise developers is that when writing a decoder, you have to think |
To summarize the POV wrt feign and why Observer.onError(Throwable) and what the impact is. Feign does not want to catch throwable :) It doesn't in the case of synchronous commands. However, in the case of async, feign is acting as a framework, managing the lifecycle of an observer as defined by onNext, onSuccess, and onError. An Observer should have the ability to at least log or increment a counter on error. It should also have a fighting chance to know that it may never complete successfully. As such, eventhough Feign propagates errors it encounters during the processing of an Observer, it will attempt to signal it via onError before propagating the error to whatever end. |
Having doubts with the name Observer here. In almost all cases where we are doing the same thing as we are here, the name is handler or callback. I think our JAX-RS 2.0 InvocationCallbackOn 2xx status
Retrofit CallbackOn 200 status Websocket Endpoint, MessageHandler + Decoder.TextStreamDecoupled interactions between Messages and Decoders, where messages deal with transport types such as byte buffers, and java types are addressed with decoders. Developers are allowed to address transport types directly by implementing
Android AsyncHttpResponseHandlerNo java type mapping, you receive the entire http content
Async HTTP Client AsyncHandlerSimilar except that the handler expects to iteratively construct the type
Apache HC FutureCallbackYou receive the http content on
Apache HC ResponseHandlerYou receive the entire http response on
|
updated above description as there are a couple cases where what we are doing is called Callback. |
Summarizing again based on input since last Friday. cc @NiteshKant @benjchristensen IncrementalCallback vs ObserverThe concept Observer is wider than what we are availing in this design. Other specs choose the word Hander or Callback. Moreover, it is best to have outside feedback where possible, so I asked Retrofit (an inspirator). Seems onError(Throwable)The design we are discussing is how to address async callbacks in a Java idiomatic way. There is value in signaling observers/callbacks on non-exception Throwables, but it is bigger than this point alone. Every current java async web callback issues throwable, not exception, for error signals. If we chose to retain Exception as opposed to Throwable, converting to or from these interfaces will be lossy. Eventhough Feign is a subset and simplification of these specs, being lossy wrt error signals is something we should take very seriously. Unless there's an extremely good reason to change course, we'll issue Throwable on error. |
…resolve_dependencies [SECURITY] Use HTTPS to resolve dependencies in Maven Build
Incremental callbacks facilitate asynchronous invocations, where the http connection and decoding of elements inside the response are decoupled from the calling thread.
In a typical synchronous response, the calling thread blocks on the http connect, reading from the socket, and also decoding of the response data into a java type. As such, a java type is returned.
In an incremental callback pattern, the calling thread blocks until the request is queued, but processing of the response (including connect, read, decode) are free to be implemented on different threads. To unblock the caller, void is returned.
Motivation
Denominator works primarily on high latency collections, where responses can take up to minutes to return. Even-though denominator returns Iterators, allowing iterative response processing, usually update granularity is per http request due to response parsing semantics of returning a list.
Ex. Sax parsing into a list which is later returned.
Ex. Incremental callback pattern allows for immediate visibility of new elements
Also, Netflix RxJava is increasingly employed, so optimizing for Observers makes sense.
IncrementalCallback Design
The following design takes from RxJava Observer and Retrofit Callback.
Why Throwable onFailure instead of Exception
The design we are discussing is how to address async callbacks in a Java idiomatic way. We issue Throwable on error instead of Exception, as Feign doesn't have a catch-all exception wrapper and Errors could be the reason why the failure occurred. This allows visibility of Errors such as AssertionErrors or thread starvation to propagate without confusing exception wrappers. It also allows us to simply propagate
exception.getCause()
without a wrapper.The above rationale supports the case for Throwable vs Exception where Feign exists in isolation. Where Feign interacts with other libraries unveils other considerations. For example, Every current java async web callback issues throwable, not exception, for error signals. If we chose to retain Exception as opposed to Throwable, converting to or from these interfaces will be lossy.
how do we make this callback asynchronous?
should we decode the response?
IncrementalCallback vs ...
In order to support asynchronous processing of http responses, we need to implement responses of Future, (RxJava) Observable, or allow users to pass in a Callback or and Observer.
As Observable is the centerpiece of RxJava's reactive pattern, it is a relatively wide interface. As such, the source for Observable.java is larger than the entire codebase of feign including tests. Making a move to couple to Observable seems overkill just to afford asynchronous invocation.
Future semantics are hard to guarantee, as operations such as cancel() rarely perform as expected with blocking i/o. For example, many implementations of http futures simply fire a callable which has no means to stop the connection or stop reading from it. Moreover timeouts are hard to make sense in future. For example connect vs read timeouts are hard to understand. Typically a response is returned after connect, but during connection you have no means to stop it. After future.get is returned, another timeout is possible reading from the stream. In summary while Future is often used, it is a tricky abstraction.
Callback and Observer approaches are simplest and incur no core dependencies. They can both be type-safe interface, such as the one in Retrofit or android-http. IncrementalCallback slightly wins as it allows for incremental parsing, and doesn't imply that Feign is Observable.
Why not reuse RxJava Observer?
RxJava Observer is not a wide interface, so much easier to grok than Observable. However, the Observer type in rx is a concrete class and implies a dependency on rxjava, a dependency which is an order of magnitude larger than feign itself. Decoupling in core, and recoupling as an extension is the leanest way to interop.
The text was updated successfully, but these errors were encountered: