-
Notifications
You must be signed in to change notification settings - Fork 31
Conversation
@pb82 Looks good. Do we use this pattern elsewhere? |
@david-martin it's the success/error callback pattern that's widely used in async languages. Not sure about Android, but since we already have The problem with Now when
There's another use in the auth module where the error handler also could be used: https://github.com/aerogear/aerogear-android-sdk/blob/master/auth/src/main/java/org/aerogear/mobile/auth/credentials/JwksManager.java#L101 (But the old method also still works) |
027eade
to
63f3ff6
Compare
} | ||
MobileCore.getLogger().debug("Metrics sent: " + json.toString()); | ||
}).onError(() -> { | ||
MobileCore.getLogger().error("Metrics request error", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@secondsun @danielpassos @wtrocki Should we log anything here? This will happen on devices out in the field, while the logs are only useful when plugged into Android Studio. Are you aware of any conventions about logging in Android apps?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great to see this example aligned with IOS:
https://github.com/aerogear/aerogear-ios-sdk/blob/master/modules/core/metrics/engine/MetricsNetworkPublisher.swift#L20-L26
This can be ok for now. For the cases when network connection is down error will be printed but that's not a big problem IMHO.
I have no strong opinion about it, but would like to keep that aligned with IOS no matter what way we would go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually this area may need more work anyway. We could handle 401/403 errors if token is wrong and print different error.
c82f277
to
9a1ee34
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched to your branch. Reviewed and verified.
@@ -43,4 +43,26 @@ public void testGet() { | |||
response.waitForCompletionAndClose(); | |||
} | |||
|
|||
@Test | |||
public void testErrorHandler() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please @pb82 rename this method accordingly with what the test case is about
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it is about testing the error handler?
assertNotNull(response); | ||
|
||
response.onComplete(() -> { | ||
// The complete handler must not be called here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call Assert.fail();
instead of comment plus forced bad assertion
9bfe841
to
9e302ba
Compare
@Override | ||
public HttpResponse onComplete(Runnable completionHandler) { | ||
this.completionHandler = completionHandler; | ||
if (response != null) { | ||
if (response != null && response.isSuccessful()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should have any if
here. I really don't care if there is a response or it was a success.
Think with me... I have raised a loading popup and wanna dismiss it when the request is complete. Complete should be called always independent of the success or fail.
At the end of the day, request should be always called runCompletionHandler
+ (runCompletionHandler
|| runErrorHandler
)
It that makes sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, understand. Then you would see the completion handler more as soemthing like a finally
? I'm ok with handling that in the completion handler but then we should probably remove the error handler because you would have to handle a possible error in your completion handler anyway.
@Override | ||
public HttpResponse onError(Runnable errorHandler) { | ||
this.errorHandler = errorHandler; | ||
if (response != null && !response.isSuccessful()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we need this kind of check here. IMO we should check only if errorHandler
is null to avoid NPE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check is required because otherwise it could happen that you attach the errorHandler when the network thread has not yet finished and response is still null. In that case we can not yet check if the response was successful and have to wait for the network thread callback to handle that.
@@ -66,8 +87,10 @@ public void waitForCompletionAndClose() { | |||
requestCompleteLatch.await(DEFAULT_TIMEOUT, TimeUnit.SECONDS); | |||
//If a completion Handler was set before this wait then we need to make sure that | |||
// gets called before we free these resources. | |||
if (completionHandler != null) { | |||
if (completionHandler != null && requestError == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like I said before if we have a completionHandler
it should be always called, not only on success
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, wouldn't that make the error handler pointless? Because then you would have to check for errors in your completion handler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danielpassos I was thinking about the same, but if you read the javadoc of the onComplete
method:
/**
* Creates a callback to be called when the response is finished successfully.
*
* The response is delivered immediately if the request has already been finished.
*/
It says that it is only called when the response is finished successfully.
If this is still the case, then I think it shouldn't be called when there is an error.
I think the name of the method is a bit confusing. I agree that if it is called onComplete
, then it should be called all the time. Otherwise it's better rename it to onSuccess
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wei-lee i'll update this PR soon to include onSuccess
, onError
and onComplete
. Complete will always be called, success only when the request was successful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pb82 👍
fa242d9
to
f5cb607
Compare
* @param runnable a callback method | ||
* @return the instance of the HttpResponse for API chaining | ||
*/ | ||
HttpResponse onSuccess(Runnable runnable); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't this pretty much make the onComplete
redundant ?
I'd assume it's no a "long-running" response, right ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@matzew it's like try
, catch
, finally
. onComplete can always be used to clean things up even when there's an error. And you would use onSuccess only if the request succeeded to do things that rely on the data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@matzew Nopz, it's the same way RxJava handler stuffs
http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Observer.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danielpassos actually, nope - Flowable
/Observable
are emitting n
objects - while Single
just emits one. See the subscribe(Consumer<? super T> onSuccess, Consumer<? super Throwable> onError)
that's why I asked if these are long-running requests, where something like onNext(ByteBuffer)
would make sense.
--
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now this API doesn't support that type of request. When the request gets done things get rolled into memory for better or worse.
runCompletionHandler(); | ||
|
||
if (!response.isSuccessful()) { | ||
throw new IOException("Request failed with status code " + response.code()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm in doubt what we should do here. The request was success called, but the response was not (range [200..300)). This should be a dev responsibility to handle that. IMO we should always call the success expect when the HTTP layer raises a problem.
@secondsun Can you give your opinion here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So first a bit of bikeshedding, IOException is the wrong exception to use here. IOException is more of a "the network quit working" type of failure.
I think that success and error handlers make a lot more sense when we start thinking about ways for modules to "rescue" a http request. If auth can refresh a token then it should be able to register as an error handler and then this distinction makes a lot of sense.
However this kind of changes the semantics a bit. A request is made. A response is returned. success and error handlers are called (which may or may not generate other network activity as appropriate) and when the whole mess has settled the completion handler has finally been called. Completion therefore stops being about a single HTTP request and is instead about a user's action in the application.
Sorry I don't think I made anything more clear LOL
f5cb607
to
3ad7ecb
Compare
@secondsun I agree with you that I've changed that to a custom Exception. @secondsun @matzew @wei-lee I was discussing this change with @danielpassos and there is one open question about the onSuccess/onError handlers: Should a response with an error code (e.g. 500) be treated as an error (onError) or treated as a successful request & response (onSuccess) and we only call onError for Network errors? I'd prefer to call What's your Opinion on this? |
@pb82 I agree with you and I think it should call |
/** | ||
* Returns the request error if it failed | ||
* @return Exception request error or null | ||
*/ | ||
Exception getRequestError(); | ||
Exception getHttpError(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about just getError?
* Custom exception thrown when a http request returns an unenxpected | ||
* result or result code | ||
*/ | ||
public class InvalidResponseException extends Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer extending runtimeexception.
3ad7ecb
to
cc02fe9
Compare
cc02fe9
to
5a1143d
Compare
@pb82 Are HTTP 302 Redirects considered errors in a response? I've updated my PR to use the changes here, but it's causing issues with Keycloak, specifically on Keycloak logouts where the result is a HTTP 302 for a successful logout.
|
@TommyJ1994 There are three possible ways to resolve this:
|
I vote for 2 |
2 for me too for flexibility. |
@secondsun @TommyJ1994 Ok, preparing a PR. |
2 is exactly what Okhttp do, they do this because there is a difference between request success and response success. We should handle only the request because there is the lib responsibility. If we could fire the request without any problem we should call success, if not we should call error. Handle the response error is the dev responsibility. |
Motivation
Allow better error handling when using the http module and fix a bug in the metrics module. When the return code from a request was 500 the
onComplete
handler was triggered. The metrics module tried to evaluate therequestError
but it was null. The current implementation does set therequestError
only when the request itself failed, not when the response returned an invalid status code.Example:
Description
Adds
onError
andonSuccess
handlers to theHttpResponse
objects. I've looked at the OkHttp recipes (https://github.com/square/okhttp/wiki/Recipes) and they seem to suggest a similar pattern for error handling.Tested with:
Progress