aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.42k stars 2.12k forks source link

Unable to reconnect AppSync after connection interruption (web) or app going into background (ios/ android) #9749

Closed CSHaze closed 1 year ago

CSHaze commented 2 years ago

Before opening, please confirm:

JavaScript Framework

Angular

Amplify APIs

Authentication, GraphQL API, DataStore, Storage

Amplify Categories

auth, storage, function, api, hosting

Environment information

``` System: OS: Windows 10 10.0.19042 CPU: (8) x64 Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz Memory: 4.43 GB / 31.96 GB Binaries: Node: 16.13.0 - C:\Program Files\nodejs\node.EXE Yarn: 1.22.10 - ~\AppData\Roaming\npm\yarn.CMD npm: 8.4.0 - C:\Program Files\nodejs\npm.CMD Browsers: Chrome: 100.0.4896.60 Edge: Spartan (44.19041.1266.0), Chromium (99.0.1150.55) Internet Explorer: 11.0.19041.1566 npmPackages: @angular-devkit/build-angular: ~13.2.1 => 13.2.5 @angular-eslint/builder: 13.0.1 => 13.0.1 @angular-eslint/eslint-plugin: 13.0.1 => 13.0.1 @angular-eslint/eslint-plugin-template: 13.0.1 => 13.0.1 @angular-eslint/schematics: 13.0.1 => 13.0.1 @angular-eslint/template-parser: 13.0.1 => 13.0.1 @angular/cli: ~13.2.1 => 13.2.5 @angular/common: ~13.2.0 => 13.2.5 @angular/common/http: undefined () @angular/common/http/testing: undefined () @angular/common/testing: undefined () @angular/common/upgrade: undefined () @angular/compiler: ~13.2.0 => 13.2.5 @angular/compiler-cli: ~13.2.0 => 13.2.5 @angular/compiler/testing: undefined () @angular/core: ~13.2.0 => 13.2.5 @angular/core/testing: undefined () @angular/forms: ~13.2.0 => 13.2.5 @angular/language-service: ~13.2.0 => 13.2.5 @angular/platform-browser: ~13.2.0 => 13.2.5 @angular/platform-browser-dynamic: ~13.2.0 => 13.2.5 @angular/platform-browser-dynamic/testing: undefined () @angular/platform-browser/animations: undefined () @angular/platform-browser/testing: undefined () @angular/router: ~13.2.0 => 13.2.5 @angular/router/testing: undefined () @angular/router/upgrade: undefined () @angular/service-worker: ~13.2.0 => 13.2.5 @angular/service-worker/config: undefined () @awesome-cordova-plugins/android-permissions: ^5.39.0 => 5.39.1 @awesome-cordova-plugins/barcode-scanner: ^5.39.0 => 5.39.1 @awesome-cordova-plugins/bluetooth-le: ^5.39.0 => 5.39.1 @awesome-cordova-plugins/camera: ^5.39.0 => 5.39.1 @awesome-cordova-plugins/core: ^5.39.0 => 5.39.1 @awesome-cordova-plugins/screen-orientation: 5.39.0 => 5.39.0 @awesome-cordova-plugins/social-sharing: ^5.39.0 => 5.39.1 @awesome-cordova-plugins/splash-screen: ^5.39.0 => 5.39.1 @awesome-cordova-plugins/status-bar: ^5.39.0 => 5.39.1 @aws-amplify/ui-angular: ^2.0.11 => 2.2.0 @aws-amplify/ui-angular/legacy: undefined () @capacitor/android: ^3.4.0 => 3.4.1 @capacitor/cli: ^3.4.0 => 3.4.1 @capacitor/core: ^3.4.0 => 3.4.1 @capacitor/ios: ^3.4.0 => 3.4.1 @capacitor/local-notifications: ^1.1.0 => 1.1.0 @ionic/angular: ^6.0.11 => 6.0.13 @ionic/angular-toolkit: ^6.1.0 => 6.1.0 @types/jasmine: ^3.8.1 => 3.10.3 @types/jasminewd2: ^2.0.10 => 2.0.10 @types/node: ^17.0.8 => 17.0.21 @typescript-eslint/eslint-plugin: ^5.9.1 => 5.13.0 @typescript-eslint/parser: ^5.9.1 => 5.13.0 asmcrypto.js: ^2.3.2 => 2.3.2 aws-amplify: ^4.3.13 => 4.3.15 buffer: ^6.0.3 => 6.0.3 (4.9.2, 5.7.1) capacitor-video-player: ^3.4.0-1 => 3.4.0 check-outdated: ^2.10.2 => 2.10.2 crypto-js: ^4.0.0 => 4.1.1 curve25519-js: 0.0.4 => 0.0.4 deep-object-diff: ^1.1.0 => 1.1.7 es6-promise-plugin: ^4.2.2 => 4.2.2 eslint: ^8.7.0 => 8.10.0 example-typescript: 1.0.0 google-protobuf: ^3.17.3 => 3.19.4 ionicons: ^6.0.1 => 6.0.1 ionicons-loader: undefined () ionicons/components: undefined () ionicons/icons: 6.0.1 jasmine-core: ^4.0.0 => 4.0.1 (2.8.0, 3.99.1) jasmine-spec-reporter: ~7.0.0 => 7.0.0 jetifier: ^2.0.0 => 2.0.0 js-sha256: ^0.9.0 => 0.9.0 karma: ~6.3.4 => 6.3.17 karma-chrome-launcher: ~3.1.0 => 3.1.0 karma-coverage-istanbul-reporter: ~3.0.2 => 3.0.3 karma-jasmine: ~4.0.0 => 4.0.1 karma-jasmine-html-reporter: ^1.7.0 => 1.7.0 node-example: 1.0.0 phonegap-plugin-barcodescanner: ^8.1.0 => 8.1.0 protractor: ~7.0.0 => 7.0.0 protractor-example: 1.0.0 rxjs: ^7.4.0 => 7.5.4 (6.6.7) rxjs/ajax: undefined () rxjs/fetch: undefined () rxjs/internal-compatibility: undefined () rxjs/operators: undefined () rxjs/testing: undefined () rxjs/webSocket: undefined () swiper: ^8.0.7 => 8.0.7 swiper_angular: 0.0.1 ts-node: ~10.4.0 => 10.4.0 ts-protoc-gen: ^0.15.0 => 0.15.0 tslib: ^2.3.0 => 2.3.1 (1.14.1) typescript: ^4.4.4 => 4.5.5 typescript-example: 1.0.0 zone-mix: undefined () zone-node: undefined () zone-testing: undefined () zone.js: ~0.11.4 => 0.11.4 zone.js/async-test: undefined () zone.js/async-test.min: undefined () zone.js/fake-async-test: undefined () zone.js/fake-async-test.min: undefined () zone.js/jasmine-patch: undefined () zone.js/jasmine-patch.min: undefined () zone.js/long-stack-trace-zone: undefined () zone.js/long-stack-trace-zone.min: undefined () zone.js/mocha-patch: undefined () zone.js/mocha-patch.min: undefined () zone.js/proxy: undefined () zone.js/proxy.min: undefined () zone.js/sync-test: undefined () zone.js/sync-test.min: undefined () zone.js/task-tracking: undefined () zone.js/task-tracking.min: undefined () zone.js/webapis-media-query: undefined () zone.js/webapis-media-query.min: undefined () zone.js/webapis-notification: undefined () zone.js/webapis-notification.min: undefined () zone.js/webapis-rtc-peer-connection: undefined () zone.js/webapis-rtc-peer-connection.min: undefined () zone.js/webapis-shadydom: undefined () zone.js/webapis-shadydom.min: undefined () zone.js/wtf: undefined () zone.js/wtf.min: undefined () zone.js/zone-bluebird: undefined () zone.js/zone-bluebird.min: undefined () zone.js/zone-error: undefined () zone.js/zone-error.min: undefined () zone.js/zone-legacy: undefined () zone.js/zone-legacy.min: undefined () zone.js/zone-patch-canvas: undefined () zone.js/zone-patch-canvas.min: undefined () zone.js/zone-patch-cordova: undefined () zone.js/zone-patch-cordova.min: undefined () zone.js/zone-patch-electron: undefined () zone.js/zone-patch-electron.min: undefined () zone.js/zone-patch-fetch: undefined () zone.js/zone-patch-fetch.min: undefined () zone.js/zone-patch-jsonp: undefined () zone.js/zone-patch-jsonp.min: undefined () zone.js/zone-patch-message-port: undefined () zone.js/zone-patch-message-port.min: undefined () zone.js/zone-patch-promise-test: undefined () zone.js/zone-patch-promise-test.min: undefined () zone.js/zone-patch-resize-observer: undefined () zone.js/zone-patch-resize-observer.min: undefined () zone.js/zone-patch-rxjs: undefined () zone.js/zone-patch-rxjs-fake-async: undefined () zone.js/zone-patch-rxjs-fake-async.min: undefined () zone.js/zone-patch-rxjs.min: undefined () zone.js/zone-patch-socket-io: undefined () zone.js/zone-patch-socket-io.min: undefined () zone.js/zone-patch-user-media: undefined () zone.js/zone-patch-user-media.min: undefined () npmGlobalPackages: @angular/cli: 13.0.2 @aws-amplify/cli: 7.6.21 @ionic/cli: 6.12.4 appium-doctor: 1.16.0 appium: 1.21.0 bower: 1.8.8 firebase-tools: 8.1.0 grunt-cli: 1.3.2 mjpeg-consumer: 2.0.0 native-run: 1.2.2 npm: 8.4.0 opencv4nodejs: 5.6.0 yarn: 1.22.10 ```

Describe the bug

When using amplify with graphql subscriptions through AppSync (angular and ionic) I often run into scenarios where the AWSAppSyncRealTimeProvider connection is disconnected and cannot be reconnected. I have experienced this on both web and mobile (ios/ android).

On Web

My application automatically severs subscriptions and resubscribes when the browser tab goes in and out of focus. This works fine.

The issue occurs when the computer is sleeping and awoken (temporary network disconnect), resulting in the below error. image

This issue also occurs when I manually stop the network connection through chrome and wait 5 minutes (the appsync keepalive timeout). image

Once either of these issues occur I cannot get my subscriptions to resubscribe. I have even tried stopping and restarting the DataStore, nothing works.

The only way to resolve the appsync socket disconnect is to refresh the browser tab.

On Mobile (ios / android)

The same issue that I am seeing on the web happens on both mobile platforms as well, when the app goes into the background.

The same as in web I sever subscriptions and resubscribe when the app goes between the background and the foreground, this works fine.

Once the app goes into the background my websocket connection seems to close and I am unable to reconnect it.

Restarting the app seems to be the only way to reconnect the websocket.

Expected behavior

I would expect the AppSyncRealTimeProvider to automatically reconnect when the network connection becomes available again.

Or to have a command that I can call to manually reconnect when the tab/app comes back into focus.

Or to be able to configure the keepAliveTimeout.

I have not found any of these to be available.

Reproduction steps

The easiest way to reproduce is using the browser to trigger offline using dev tools and wait 5 minutes.

  1. Start the app, observe subscriptions are working correctly.
  2. In dev tools select offline mode to simulate a network disconnect.
  3. Wait 5 minutes.
  4. Attempt to subscribe (or resubscribe) to appsync topics.
  5. Observe the AWSAppSyncRealTimeProvider error indicating the web socket has been closed.
  6. Subscriptions no longer work.

This can also be replicated on mobile by putting the app into the background.

Code Snippet

if (isInForeground) {
         // subscribe to app topics
} else {
      // unsubscribe from app topics
}

Log output

``` // Put your logs below this line ```

aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

Iphone 12, Pixel 3

Mobile Operating System

iOS 15.3.1, Android 11

Mobile Browser

Chrome

Mobile Browser Version

No response

Additional information and screenshots

No response

chrisbonifacio commented 2 years ago

Hi @CSHaze please follow this PR for future updates on this feature being implemented.

CSHaze commented 2 years ago

@chrisbonifacio this is awesome! Thank you

stocaaro commented 1 year ago

Reconnection is now staged on the next tag in preparation for release in aws-amplify v5. To test against this update install the next tag version of the aws-amplify packages your project is using. eg yarn add aws-amplify@next.

With this change any disrupted connection will attempt to reconnect when possible. Reconnection can be expected to trigger 5 seconds after the resources to reconnect are available. If the network is disrupted in a way that can't be detected, reconnection will be attempted every minute until the connection is recovered.

Note that missed messages will not backfill on recovery. If you need to trigger behavior to catch up missed messaged on recovery, this should be possible to implement using the connection state Hub messages released last month.

Ilya93 commented 1 year ago

Reconnection is now staged on the next tag in preparation for release in aws-amplify v5. To test against this update install the next tag version of the aws-amplify packages your project is using. eg yarn add aws-amplify@next.

With this change any disrupted connection will attempt to reconnect when possible. Reconnection can be expected to trigger 5 seconds after the resources to reconnect are available. If the network is disrupted in a way that can't be detected, reconnection will be attempted every minute until the connection is recovered.

Note that missed messages will not backfill on recovery. If you need to trigger behavior to catch up missed messaged on recovery, this should be possible to implement using the connection state Hub messages released last month.

When this will be published to main ?

stocaaro commented 1 year ago

When this will be published to main ?

Today!


Good news. Automated Reconnection is now available on the latest aws-amplify release! Review the updated subscription docs and consider any application behavior you may want to add to best meet your users needs when subscriptions reconnect.

Please review our breaking change guidance before upgrading your application.

To upgrade Amplify to version 5, run the following in your project folder:

yarn add aws-amplify@latest

Check package.json to see if your project uses other @aws-amplify/* packages directly and upgrade them to latest as well.

With this behavior released, I am closing this issue as resolved.

dylan-westbury commented 1 year ago

Hi @stocaaro,

Will this update only work for the Amplify GraphQL client and not the AWS AppSync JavaScript SDK?

stocaaro commented 1 year ago

Hello @dylan-westbury,

Correct that the reconnect changes were applied to Amplify and haven't been applied to the AppSync SDK. There are a few issues (ex) on that package related to this.

Thanks, Aaron

pepemiso16 commented 1 year ago

Hi @stocaaro, will there be any update for the SDK for this issue? Thanks

stocaaro commented 1 year ago

I am not aware of any work aimed to port reconnection back to the SDK package. I would recommend surfacing your need on one of the tickets that captures this gap.

dylan-westbury commented 1 year ago

https://github.com/awslabs/aws-mobile-appsync-sdk-js/issues/740 for AWS AppSync JavaScript SDK equivalent of this bug.