#[CloudServices] Proper Usage of 'SynchronizeCompleted'.

1 messages · Page 1 of 1 (latest)

untold sage
#

Since resetting or testing iCloud Key-Value Storage isn’t easy, I’d like to ask for your advice—since you probably know it well.

It is about how to properly use "OnSynchronizedCompleted".
Let’s assume the game data includes a "timestamp(long)" field that is frequently updated.

After the app launches, the first scene explicitly calls "Synchronize()", and in the "SynchronizeCompleted" callback, it compares the "timestamp" values of the Server Copy and the Local Copy.

My logic is as follows.

  1. Only if the Server Copy is newer, it overwrites the Local Copy with the Server Data.
  2. But if the Local Copy is newer, it does nothing—since it will be synced during the next periodic Synchronize() call anyway. (Of source, manually pushing local data to the server can be a good idea, but I just prefer to reduce the use of traffic)

In short, I wonder the above logic which comparing timestamps and conditionally overwriting data inside the "SynchronizeCompleted" callback is a good idea?

This is not so much a question as it's seeking your opinion. I'd appreciate any small feedback you can give. Thank you.

untold sage
#

I bet you're super busy now and don't have a minute to leave a single line of comment. 😢
Thanks for that thumb emoji though.

modern adder
#

I'm trying to give an example so that it helps better 😄
On it!

#

Scenario 1 : timestamp has latest value in local and stale value in cloud

  1. Sync call
  2. As local and cloud are diff, local will be replaced with cloud
  3. We fire OnSavedDataChange event
  4. We call SynchronizeComplete event

In #3, you can check latest value which was in local copy earlier with CloudServicesUtility.TryGetCloudAndLocalCacheValues. Get the value and compare with CloudServices.GetXXX (notice that this has cloud value which was downloaded and overwrite local copy in #2).

If value from TryGetCloudAndLocalCacheValues is "right" value, just use CloudServices.SetXXX and set the value. Else just do nothing as the value in the current local copy is latest.

#

Scenario 2 : timestamp has same value in local and cloud

  1. Sync call
  2. As local and cloud are same for this key, nothing happens for this key
  3. We call SynchronizeComplete event
#

Note that in scenario 1 - If cloud copy was earlier committed from the same device, you don't get the OnSavedDataChange as it's not a conflict. - We maintain tags internally to achieve this.
If we don't do this, you keep getting OnSavedDataChange for every change you make - which is unnecessary

#

Just ignore any checks and handle in the OnSavedDataChange correctly. We already do the required optimisation internally but one thing you need to be aware.

Only call sync when you see it important and not too often. So you can keep using the CloudServices.SetXXX anytime and just call Sync at checkpoints.

#

Hope it clarifies your concern.

untold sage
#

Sorry, man. I would not like to bother you any more, but it is very confusing for me to understand how 'CloudServices' works.

To save your time, I read and read again what you said instead of asking you more questions, but now everything gets even more vague.

  1. You said that 'OnSavedDataChange' does not fire on the same device (and same account).
    But, I think conflict cases can happen even though I use the same device (and same account).
    ** => [Conclusion] This is right. It does not fire 'OnSavedDataChange' on the same device.**
#

▶ Scenario C. (Returning Player)
You quit playing the game and removed the app, but after some days, you came back and re-installed the game. (still same device, same account)
Local data (empty) / Server data (latest)
** => [Conclusion] By design, 'OnSavedDataChange' has to be fired with reason of 'InitialSync' for this case. However, my actual tests confirmed I do not get 'OnSavedDataChange'. My research also back this result. If you remove the app and app data on the same device and re-install the app shortly after, you may not receive 'OnSavedDataChange'.
**

untold sage
#

**=> [Conclusion]

  • "Synchronize()" : call once at launch, and call it whenever major changes happen. (but not too often). this manual call to request 'synchronization' is likely to perform soon, but not guaranteed when exactly it's gonna be completed.

  • "SynchronizeCompleted" : If there's possibility not to get "OnSavedDataChange" but Local Data and Cloud Data differ, you need to deal with the conflict resolution here.

  • "OnSavedDataChange" : basically this is a place for conflict resolution, but the primary use of this event is for multiple devices scenarios.

  • "Getters & Setters" : works with local cache (latest downloaded cloud copy), and this is a middle layer of actual local data and cloud data, and I cannot accurately handle this middle area.**

modern adder
#

There are multiple edge cases for these and I actually take the total responsibility for the ambiguity.
I'm preparing a separate doc on the different scenarios possible including offline scenarios for a clear understanding as I believe there is a need. This concept is actually confusing for many and needs some background on how it's handled on native.
While we try to abstract the native handling, there are some concepts which needs to be communicated to the user for better understanding.

untold sage
#

I updated my messages above with the conclusions that I have now.

The confusion mostly came from the abstract concepts of 'Local Copy', 'Server Copy', 'Latest downloaded Cloud Copy'..

After lots of trials and extra research about iCloud KVS, I could understand how it works. Finally I was able to write proper code that perfectly works. Clearly defining the meaning of key concepts from the client’s perspective, the meaning of them from the server’s perspective, and the timing at which synchronization occurs was required to do so.

Thanks.

We may close this issue.

cursive gale
#

I believe there is a race condition, which I have been able to repro. If you call CloudServices.SetString() then Synchronize() to ensure it's saved, you can get a OnSavedDataChange(ServerChange) callback about the change you just did, and the cloud data will be the "old" data, not what you are in the process of saving. You will get the OnSynchronizeComplete() callback soon after. Or you may not get the OnSavedDataChange() call at all and only OnSynchronizeComplete().