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.43k stars 2.13k forks source link

DataStore on Angular doesn't sync to other devices #5923

Closed edoardo849 closed 4 years ago

edoardo849 commented 4 years ago

Describe the bug Using DataStore with Angular by testing with multiple clients (different browsers): when I create an Item on browser 1 I can see the result in DynamoDB and receive an update via the local subscription on browser 1. However, the local subscription on browser 2 isn't triggered and I need to refresh the page completely on browser 2 in order to see the change performed on browser 1.

To Reproduce Steps to reproduce the behavior:

  1. Have 2 browsers side by side with the same User logged in
  2. Add / Delete an Item in browser 1
  3. The item gets added / deleted in browser 1, both in the local IndexedDB and in DynamoDB
  4. The local subscription in browser 1 receives a msg
  5. The item doesn't get updated in browser 2 and the subscription doesn't receive any msg
  6. The item doesn't get updated on browser 2 even after querying it again on browser 2 with DataStore.query(...) .
  7. The item gets finally synced on browser 2 only when browser 2 gets refreshed

Expected behavior When creating / deleting an item in browser 1, I would expect the same operation to happen automatically and in near-real-time in browser 2.

Code Snippet

backend/api/app/schema.graphql


enum Status {
  OK
  NOTOK
}

type Recording @model @auth(rules: [{ allow: owner }]) {
  id: ID!
  name: String!
  description: String
  status: Status
}

main.ts

...
import Amplify from '@aws-amplify/core';
Amplify.configure(awsconfig);
...

app.component.ts

async ngOnInit() {
    await this.loadItems();
    this._recordingSub = DataStore.observe(Recording).subscribe(this.loadItems);
}

async loadItems() {
    try {
      const items = await DataStore.query(Recording);
      console.log("Loaded items", items);
      this.recordings = items;
    } catch (e) {
      console.error(e);
    }
  }

async createRecording() {

    try {
      const msg = await DataStore.save(new Recording({
        name: "Test",
        description: "Test",
        status: Status.OK
      }));

      console.log("message", msg)
    } catch (e) {
      console.error(e)
    }
  }

ngOnDestroy() {
    this._recordingSub.unsubscribe();
  }

I am running the app with ng serve --prod

What is Configured? If applicable, please provide what is configured for Amplify CLI:


amplify api update
? Please select from one of the below mentioned services: GraphQL
? Select from the options below Walkthrough all configurations
? Choose the default authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project.
? Do you want to configure advanced settings for the GraphQL API Yes, I want to make some additional changes.
? Configure additional auth types? No
? Configure conflict detection? Yes
? Select the default resolution strategy: Auto Merge
? Do you want to override default per model settings? Yes
? Select the models from below: Recording
? Select the resolution strategy for Recording model: Auto Merge

GraphQL schema compiled successfully.
  const awsmobile = {
    "aws_project_region": "eu-west-2",
    "aws_cognito_identity_pool_id": "eu-west-xxxx",
    "aws_cognito_region": "eu-west-2",
    "aws_user_pools_id": "eu-west-2_xxxx",
    "aws_user_pools_web_client_id": "xxxx",
    "oauth": {},
    "aws_appsync_graphqlEndpoint": "https://xxxx.appsync-api.eu-west-2.amazonaws.com/graphql",
    "aws_appsync_region": "eu-west-2",
    "aws_appsync_authenticationType": "AMAZON_COGNITO_USER_POOLS"
};

Environment

System:
    OS: Linux 4.19 Ubuntu 18.04.4 LTS (Bionic Beaver)
    CPU: (8) x64 Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz
    Memory: 5.93 GB / 12.35 GB
    Container: Yes
    Shell: 4.4.20 - /bin/bash
  Binaries:
    Node: 14.1.0 - ~/.nvm/versions/node/v14.1.0/bin/node
    npm: 6.14.5 - ~/.nvm/versions/node/v14.1.0/bin/npm
  npmPackages:
    @angular-devkit/build-angular: ^0.901.7 => 0.901.7 
    @angular/animations: ^9.1.9 => 9.1.9 
    @angular/cli: ^9.1.7 => 9.1.7 
    @angular/common: ^9.1.9 => 9.1.9 
    @angular/compiler: ^9.1.9 => 9.1.9 
    @angular/compiler-cli: ^9.1.9 => 9.1.9 
    @angular/core: ^9.1.9 => 9.1.9 
    @angular/forms: ^9.1.9 => 9.1.9 
    @angular/platform-browser: ^9.1.9 => 9.1.9 
    @angular/platform-browser-dynamic: ^9.1.9 => 9.1.9 
    @angular/router: ^9.1.9 => 9.1.9 
    @aws-amplify/auth: ^3.2.9 => 3.2.9 
    @aws-amplify/core: ^3.2.9 => 3.2.9 
    @aws-amplify/datastore: ^2.1.2 => 2.1.2 
    @aws-amplify/ui-angular: ^0.2.6 => 0.2.6 
    @types/jasmine: ~3.5.0 => 3.5.10 
    @types/jasminewd2: ~2.0.3 => 2.0.8 
    @types/node: ^12.12.42 => 12.12.42 
    bulma: ^0.8.2 => 0.8.2 
    codelyzer: ^5.1.2 => 5.2.2 
    jasmine-core: ~3.5.0 => 3.5.0 
    jasmine-spec-reporter: ~4.2.1 => 4.2.1 
    karma: ~5.0.0 => 5.0.9 
    karma-chrome-launcher: ~3.1.0 => 3.1.0 
    karma-coverage-istanbul-reporter: ~2.1.0 => 2.1.1 
    karma-jasmine: ~3.0.1 => 3.0.3 
    karma-jasmine-html-reporter: ^1.4.2 => 1.5.4 
    protractor: ~5.4.3 => 5.4.4 
    rxjs: ~6.5.4 => 6.5.5 
    ts-node: ~8.3.0 => 8.3.0 
    tslib: ^1.10.0 => 1.13.0 
    tslint: ~6.1.0 => 6.1.2 
    typescript: ~3.8.3 => 3.8.3 
    zone.js: ~0.10.2 => 0.10.3 
  npmGlobalPackages:
    @angular/cli: 9.1.6
    @aws-amplify/cli: 4.21.0
    create-react-app: 3.4.1
    npm: 6.14.5

Additional Context

If I switch from DataStore to GraphQL only (without local sync), then the subscription works as expected and I can see the message on both browsers.

schema.graphql


enum Status {
  OK
  NOTOK
}

type Recording @model @auth(rules: [{ allow: owner }]) {
  id: ID!
  name: String!
  description: String
  status: Status
}

type Subscription {
  onCRUDRecording: Recording
    @aws_subscribe(
      mutations: ["createRecording", "updateRecording", "deleteRecording"]
    )
}

app.component.ts


async loadItems() {

    try {
      const data = await this._api.ListRecordings();
      console.log("Loaded items", data);
      this.recordings = data.items;
    } catch (e) {
      console.error(e);
    }
  }

  async ngOnInit() {

    this._api.OnCrudRecordingListener.subscribe(msg => {
      console.log('Something happened"', msg);
    });
}

async createRecording() {

    this._api.CreateRecording({
      name: 'Angular',
      description: 'testing'
    });
}
ashika01 commented 4 years ago

@edoardo849 - Could you update to our unstable version and try if this still exists. we have introduced some major changes to datastore.

These are the unstable versions, you might need to use --save-exact due to semver's handling of build metadata

@aws-amplify/analytics@3.1.13-unstable.5
@aws-amplify/api-graphql@1.0.15-unstable.5
@aws-amplify/api-rest@1.0.15-unstable.5
@aws-amplify/api@3.1.13-unstable.5
@aws-amplify/auth@3.2.10-unstable.5
@aws-amplify/cache@3.1.13-unstable.5
@aws-amplify/core@3.2.10-unstable.5
@aws-amplify/datastore@2.1.3-unstable.5
@aws-amplify/interactions@3.1.13-unstable.5
@aws-amplify/predictions@3.1.13-unstable.5
@aws-amplify/pubsub@3.0.14-unstable.5
@aws-amplify/pushnotification@3.0.14-unstable.5
@aws-amplify/storage@3.2.3-unstable.5
@aws-amplify/ui-angular@0.2.7-unstable.9
@aws-amplify/ui-components@0.5.1-unstable.9
@aws-amplify/ui-react@0.2.8-unstable.9
@aws-amplify/ui-vue@0.2.7-unstable.9
@aws-amplify/ui@2.0.3-unstable.168
@aws-amplify/xr@2.1.13-unstable.5
amazon-cognito-identity-js@4.3.1-unstable.9
aws-amplify-angular@5.0.14-unstable.5
aws-amplify-react-native@4.2.1-unstable.9
aws-amplify-react@4.1.13-unstable.5
aws-amplify-vue@2.1.2-unstable.168
aws-amplify@3.0.14-unstable.5
ashika01 commented 4 years ago

I am seeing some problems in firefox and safari (working on this) but everything seems to work perfectly in chrome.

ashika01 commented 4 years ago

@edoardo849 My issues with firefox and safari was due my cached old indexed db. Clearing the local data and trying it again solved it.

With respect to your refresh problem, with the latest unstable version, we have introduced datastore sync status. You can make use of it for sync to happen properly.

async ngOnInit(): Promise<void> {
    this.removeHubListener = Hub.listen('datastore', async ({payload: {event}}) => {
      if(event === 'ready') {
        await this.query();
      }
    });
  }

  ngOnDestroy(): void {
    this.removeHubListener();
  }

public async query() {
    const predicate: typeof Predicates.ALL = Predicates.ALL;
    const pagination: PaginationInput = { page: this.page, limit: this.limit };

    this.notes = await DataStore.query(Note, predicate, pagination);
  }

Let us know how it goes.

edoardo849 commented 4 years ago

Hey @ashika01 thanks for your reply! I'm testing it today and will update asap how it goes :-)

stale[bot] commented 4 years ago

This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems.

github-actions[bot] commented 3 years ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.