Skip to content
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

Implement auto reconnect for WebSocketConnectionManager #318

Merged
merged 3 commits into from
Nov 12, 2020

Conversation

mxalbert1996
Copy link
Contributor

@mxalbert1996 mxalbert1996 commented Oct 6, 2020

Issue #, if available: #317

Description of changes:
Implemented auto reconnect for WebSocket-based subscriptions in WebSocketConnectionManager based on legacy implementation in RealSubscriptionManager.
Also added result check for WebSocket.send(). This fixes the bug that further subscriptions after the WebSocketListener's onFailure callback will fail silently because once failed WebSockets cannot be used any more.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@mxalbert1996 mxalbert1996 force-pushed the websocket-auto-reconnect branch from cced50b to 8eb5e5d Compare October 7, 2020 04:11
@mxalbert1996
Copy link
Contributor Author

Just observed this crash (occasionally) when trying to reconnect with no internet access.

com.amazonaws.AmazonClientException: Unable to execute HTTP request: Unable to resolve host "cognito-identity.ap-northeast-1.amazonaws.com": No address associated with hostname
    at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:441)
    at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:212)
    at com.amazonaws.services.cognitoidentity.AmazonCognitoIdentityClient.invoke(AmazonCognitoIdentityClient.java:1728)
    at com.amazonaws.services.cognitoidentity.AmazonCognitoIdentityClient.getCredentialsForIdentity(AmazonCognitoIdentityClient.java:750)
    at com.amazonaws.auth.CognitoCredentialsProvider.populateCredentialsWithCognito(CognitoCredentialsProvider.java:783)
    at com.amazonaws.auth.CognitoCredentialsProvider.startSession(CognitoCredentialsProvider.java:695)
    at com.amazonaws.auth.CognitoCredentialsProvider.getCredentials(CognitoCredentialsProvider.java:466)
    at com.amazonaws.auth.CognitoCachingCredentialsProvider.getCredentials(CognitoCachingCredentialsProvider.java:481)
    at com.amazonaws.auth.CognitoCachingCredentialsProvider.getCredentials(CognitoCachingCredentialsProvider.java:78)
    at com.amazonaws.mobileconnectors.appsync.SubscriptionAuthorizer.getAuthorizationDetailsForIAM(SubscriptionAuthorizer.java:133)
    at com.amazonaws.mobileconnectors.appsync.SubscriptionAuthorizer.getAuthorizationDetails(SubscriptionAuthorizer.java:83)
    at com.amazonaws.mobileconnectors.appsync.SubscriptionAuthorizer.getConnectionAuthorizationDetails(SubscriptionAuthorizer.java:62)
    at com.amazonaws.mobileconnectors.appsync.WebSocketConnectionManager.getConnectionRequestUrl(WebSocketConnectionManager.java:373)
    at com.amazonaws.mobileconnectors.appsync.WebSocketConnectionManager.createWebSocket(WebSocketConnectionManager.java:130)
    at com.amazonaws.mobileconnectors.appsync.WebSocketConnectionManager.retryAllSubscriptions(WebSocketConnectionManager.java:307)
    at com.amazonaws.mobileconnectors.appsync.WebSocketConnectionManager.access$900(WebSocketConnectionManager.java:44)
    at com.amazonaws.mobileconnectors.appsync.WebSocketConnectionManager$3.handleMessage(WebSocketConnectionManager.java:250)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:193)
    at android.os.HandlerThread.run(HandlerThread.java:65)
Caused by: java.net.UnknownHostException: Unable to resolve host "cognito-identity.ap-northeast-1.amazonaws.com": No address associated with hostname
    at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:126)
    at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:105)
    at java.net.InetAddress.getAllByName(InetAddress.java:1154)
    at com.android.okhttp.Dns$1.lookup(Dns.java:39)
    at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:175)
    at com.android.okhttp.internal.http.RouteSelector.nextProxy(RouteSelector.java:141)
    at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:83)
    at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:174)
    at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
    at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
    at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
    at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:461)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127)
    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:258)
    at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)
    at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:26)
    at com.amazonaws.http.UrlHttpClient.writeContentToConnection(UrlHttpClient.java:162)
    at com.amazonaws.http.UrlHttpClient.execute(UrlHttpClient.java:75)
    at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:371)
	... 19 more

According to this, it seems that this exception happens when there's no internet connection and needs to be caught manually. Will add that to this PR.

Comment on lines +87 to +88
final NetworkInfo info = connManager.getActiveNetworkInfo();
return info != null && info.isConnected();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This rarely means that there is internet connectivity, unfortunately.

  1. The active network may be a WiFi network at a coffee shop that imposes a captive portal;
  2. The active network may be up, but not serving packets.

Consequently, it is better to just try network activities, and if they work, they work, if they fail, do exponential backoff with retries.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that this doesn't necessarily mean there is internet connectivity but there is a chance, so IMHO trying once when a network becomes available doesn't hurt but can dramatically reduce the time needed to resume if there is internet access because of exponential backoff.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. It was also pointed out to me that this is the existing behavior of the non-WebSocket branch, too.

@raphkim raphkim merged commit 9431477 into awslabs:main Nov 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants