In My Movie, we have a global “videoId” counter that is incremented 1 to assign to a video ID. We do this so that we can play random videos by picking a number 1 through videoId.
However, we are getting a bug where this :IncrementAsync(1) call will sometimes return the same value, dropping the in-between.
When did this issue start to happen? Assume you are incrementing this key across many game servers, how do you handle failures from IncrementAsync? Feel free to DM me with more info if there are information you don’t want to share publicly.
This started happening over the past few days, but I can’t say it’s a regression–our game just recently released and we have had explosive growth, and thus more chances for this to occur.
I am not sure what you mean about handling failures from IncrementAsync. If you mean errors, we stop the video upload and ask the user to try again. If you mean these atomic inconsistencies, I unfortunately don’t have an answer–we are just losing the data because two videos upload to the same ID.
In the most recent update I have replaced IncrementAsync with UpdateAsync, and I haven’t gotten reports of it happening yet.
Let us know if this issue still happens to you with UpdateAsync. At that point it would be very helpful if you can share some scripts of how your game uses the DataStores APIs.
Update: I removed the part mentioning that IncrementAsync is similar to SetAsync. After discussing within the team, we believe that’s indeed a bug and working on a fix right now. After the fix is live, IncrementAsync will become atomic (again).
If IncrementAsync is not meant to be atomic, I would definitely put that in the documentation! Everyone I’ve described this to has assumed that this is the case.
The code itself is wrapped up in some abstractions, but it essentially logically boils down to:
local success, problem = pcall(function()
local nextVideoId = videoIdStore:IncrementAsync(1)
videoStore:SetAsync(nextVideoId, video)
end)
It is now (essentially):
local success, problem = pcall(function()
local nextVideoId
videoIdStore:UpdateAsync(function(currentVideoId)
local finalVideoId = currentVideo + 1
nextVideoId = finalVideoId
return finalVideoId
end)
videoStore:SetAsync(nextVideoId, video)
end)
I always assumed it was atomic as well, and am glad I never used it! The way most people have used it over the years (to my knowledge) seems like it was meant to be atomic, but never actually was. It doesn’t seem useful for much outside of being a simple way to increment something atomically, so the documentation should definitely be changed.
I made an update to my earlier post. We believe IncrementAsync should be atomic and are working on a fix. In addition to that, the exact behavior will be documented after the fix is live.
The fix for IncrementAsync is live and you can expect each IncrementAsync call will return a different value. However, if multiple IncrementAsync is invoked and processed at the same time, there is no guarantee on the order of processing.