Is it possible to see the source of the DataStore changes coming from sync?

0

in the web app using Amplify & Datastore

I am updating the app UI based on the changes from the server on sync (DataStore.observe/subscribe) When change is made by the particular client - I update the UI first (optimistic approach) and saving data to DataStore in a background.

There is a self conflict issue when the user continues to change the data and the previous save comes back via DataStore subscription - is there a way to see that the change was made by the very same client to skip the sync (as current version de facto is the newest one) Or what is the generally best approach in such cases?

On DataStore events documentation page[1] there is "source" field, which is empty by default. Is it possible to configure each client to fill that field with its ID?

[1] -https://docs.amplify.aws/lib/datastore/datastore-events/q/platform/js/#usage (see the source on "modelSynced" and other events data )

Arsen
asked a year ago359 views
2 Answers
1
Accepted Answer

Hello, I understand that you would like to know when change is made by the particular client and saving data to DataStore in a background, is there a way to see that the change was made by the very same client to skip the sync for other clients via DataStore subscription. Further, you would also like to know it possible to configure each client to fill “source” field with its ID in the Datastore events which is empty by default.

Unfortunately, as of now it is not possible to customize the DataStore events. Further, the GraphQL mutation performed by a client will result in every client receiving a WebSocket message with that change. Hence, currently there is no workaround to see that the change was made by a specific client to skip the sync for others. I have reached out to our service team and they have considered it as a AppSync Service limitation and are already aware of this.

Having said that, I understand that the lack of the feature is causing inconvenience and I sincerely apologize on behalf of AWS for the inconvenience caused to you due to this service side limitation. I would also recommend you to raise a Github issue on AWS AppSync official repository. Please be assured that our internal team takes customer’s feedback seriously and are always looking at ways to improve the service. However, I am unable to comment on when a fix get released by service team in near future. You may keep an eye on the GitHub issue raised by you for tracking this issue.

In case I misunderstood the query, please feel free to reach out to us via creating a support case from the support centre dashboard.

AWS
SUPPORT ENGINEER
Ankit_V
answered a year ago
  • Hi thanks for the response. I think you understand the question right, although "currently there is no workaround to see that the change was made by a specific client to skip the sync for others" Is not accurate I want to skip the update for the user that made the original change, not the others.

    If I would block the possibility to change while I wait for the DataStore save to finish the problem would not accrue.

0

I found an acceptable workaround for my use case. I made the updatedAt field editable by adding it to the scheme manually. updatedAt: AWSDateTime! And with each update I save the (new Date()).toISOString() I set to the updatedAt field locally. It allows me to guess that the msg coming from subscribe is caused by the user that have that time stored locally.

It feel that I'm mistaken at the whole approach and maybe it is better to simply block UI, plus there is a separate issue with conflict resolving to consider as well.

I'am not sure it this will help anyone else, but I will leave some example code here:

const updateWorkspace = async (workspaceId: string, mutator: (any: any) => void) => {
    /* @ts-ignore ReadOnly fields have type issue on amplify DataStore.query types  */
    const workspace = await DataStore.query(Workspace, workspaceId);
    const updateTimeISO = (new Date()).toISOString();
    changeHistory.pinStep(updateTimeISO);

    return await DataStore.save(
        Workspace.copyOf(workspace!, (updated) => {
            mutator(updated);
            updated.updatedAt = updateTimeISO;
        })
    );
}
let pendingSteps = new Set<string>();
export const changeHistory = {
    pinStep: (time: string) => {
        pendingSteps.add(time);
    },
    clearSteps: () => {
        pendingSteps.clear();
    },
    removeStep: (step: string) => {
        pendingSteps.delete(step);
    },
    isChangeLocal: (workspace: EagerWorkspace) => {
        return pendingSteps.has(workspace.updatedAt!);
    }
}

DataStore.observe(Workspace, workspaceMST.id).subscribe(syncWorkspace(workspaceMST))

const syncWorkspace = (workspaceMST: WorkspaceModelType) => async (msg: InternalSubscriptionMessage<Workspace>) => {
    const serverWorkspace = msg.element;
    /* @ts-ignore */
    const serverVersion = serverWorkspace._version;

        if (changeHistory.isChangeLocal(serverWorkspace)) {
                /* Do nothing with UI it may be in a newer state that one coming from the sync */
                return;
        }
        /* sync UI, in my case it's Mobx Store */
    }
}
Arsen
answered a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions