Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

When to use SetAsync and when to use UpdateAsync?

Asked by 8 years ago

So I've been reading this article on the wiki about saving player data, but something seemed a bit weird to me. (Here's the link: http://wiki.roblox.com/index.php?title=Saving_Player_Data)

In their example, they demonstrated making a save data function using only SetAsync, but in their article explicitly about the data store service (along with it's API), they say how using only SetAsync to save existing data can be dangerous, since GetAsync can return cached data.

Here's the function they gave in their article that is somewhat controversial to me:

local function savePlayerData(player)
    playerData:SetAsync(player.UserId, sessionData[player]) -- SetAsync to save EXISTING data?
end

-- And now we're going to use it in a loop?
local function autosave()
    while wait(AUTOSAVE_INTERVAL) do
        for player, data in pairs(sessionData) do
            savePlayerData(player)
        end
    end
end

Here's the quote from the original wiki article documenting the data store's SetAsync function:

"Sets the value of the key. This overwrites any existing data stored in the key. If the previous value of the key is important, use UpdateAsync. Using GetAsync to retrieve a value and then setting the key with SetAsync is dangerous because GetAsync sometimes returns cached data, and other game servers may have modified the key"

(Initial data store article here: http://wiki.roblox.com/index.php?title=Data_store)

So... Are there some exceptions to when you can use SetAsync to save existing data, does it not matter, or did they just make a mistake?

If anyone could clear this up for me, I'd really appreciate it. Thanks.

0
It's looks like data for individual players is fine to use setAsync, but data that's used across multiple games at the same time (like total kills across everyone who's ever played) would need updateAsync to make sure nothing is lost. GoldenPhysics 474 — 8y

1 answer

Log in to vote
1
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
8 years ago

When it comes down to it, this is about race conditions.

Because the game server and datastore server are in physically different machines, it can take quite a bit of time for reads and writes to happen.

If you did something like

a = Data:Read()
print(a) --> 10
Data:Write(11)
b = Data:Read()

print(b) --> 10

You'll probably not get the 11 out. This is further complicated by having many different servers all talking to the data store at the same time. You have to make sure your code will never "compete" with other reads/writes.

:UpdateAsync let's you avoid this trouble most of the time. It gives you the current value, and guarantees no one else will write before you do.


Only if the current value does not depend at all on the previous value (not even on a variable that was loaded from that in the data store) is it for sure safe to use :SetAsync, or if you are sure that no other writes will happen at the same time.

Examples of this might be

  • Write the current time to an associated user id when they join

    • does not depend on previous value
    • no other writes happening since player only joining 1 server, and it only happens once
  • Updating only when the player leaves, or only once in a while, for a particular player * player is only in one server at a time * writes have almost no probability of conflicting since they are far apart * close together writes are unlikely to disagree


If you ever have something like Set( Get() + 1 ), you should not be using SetAsync and should be using UpdateAsync

Ad

Answer this question