Right now GetAsync is unreliable. There’s no way of knowing if the data it gives you is old, because it caches. The only way to be sure the data you’re getting is correct is to use UpdateAsync instead and start using up the set limit rather than the get limit. That’s not what I want to do. Http GetAsync has a nocache parameter, so data stores should have it as well, otherwise GetAsync is unsafe.
Possible workaround: Could you just store it locally and use OnUpdate to update your own local cache?
local kills = dataStore:GetAsync("kills")
dataStore:OnUpdate("kills", function(value)
kills = value
end)
Possible downside with this is the data limits for OnUpdate.
Edit: You could even create an event around it:
local kills = dataStore:GetAsync("kills")
local killsChanged = Instance.new("BindableEvent")
dataStore:OnUpdate("kills", function(value)
kills = value
killsChanged:Fire(value)
end)
killsChanged.Event:Connect(function(newKills)
print("Kills: " .. newKills)
end)
I know you don’t want to use the set limit for this but I thought I’d post about how to use UpdateAsync to bust the cache for anyone who doesn’t know.
If you are using UpdateAsync as a way to avoid the cache you need to also update the data when you read it (otherwise it can still be cached data). The best way to do this is something like the following:
local kills = 0
-- This should be in a retry loop with failure handling
pcall(function()
DataStore:UpdateAsync("PlayerData", function(oldData)
local newData = oldData or {
Kills = 0,
LastUpdated = os.time()
}
-- Update the data, this ensures that you won't only read from the cache.
newData.LastUpdated = os.time()
-- Read whatever field you want
kills = newData.Kills
return newData
end)
end)
Not updating the data when trying to use UpdateAsync to bust the cache is a common mistake I’ve seen, not doing this means you will still read the cached value.
Why would UpdateAsync be giving me outdated data to make changes to? I only want to make changes to the newest data. That’s like if IncrementAsync cached, it doesn’t make any sense. If it gives me outdated data then I’ll be overwriting the up to date data with a combination of outdated data and new up to date data.
UpdateAsync is implemented like a compare and swap loop.
This means the cached value is initially passed to your update function, your function executes on this value and produces a new value. Both the old value and the new value are sent to the DataStore where the operation only goes through if the oldValue is equal to the value currently in the DataStore for that key. If the value currently in the key is different then that value is returned and your update function is called again with the value that’s currently in the key.
If your function doesn’t actually update the data the loop will exit early and you won’t see the true value in the DataStore. For this reason you need to actually update the data to not hit the cache.
Would using GetAsync once and then connecting to OnUpdate initially give you an up to date value? What if I disconnect OnUpdate and later on call GetAsync and re-connect OnUpdate to start listening to that key again?
I have multiple servers that can be writing to the same keys. I want each server to stay up to date on each key they’re listening to and only use UpdateAsync when they actually want to make a change. The issue I’m having is there’s no way to get the latest data without trying to make a change and using up the set limit. Even using OnUpdate is more than I would like to do. I just want to call either GetAsync or UpdateAsync, depending on whether the server has a change to make, once every 10 seconds.
When OnUpdate is connected the cached value for that key is re-fetched every minute or so (if you go over the limit for OnUpdate keys each key is re-fetched less). Using OnUpdate doesn’t guarantee that you have the most recent data, it could be a minute out of date.
Unfortunately you are right, there is no way to do this currently.