Since about one or two days I’m getting a heavy increase in the amount of reports that saving fails in my game. This isn’t due to a random Roblox service outage (which usually explain those failures).
GetAsync is not affected and always works fine.
After checking the output with some affected user, I’ve came to the conclusion that HTTP error 429 was triggered every time, which, according to Google means it’s caused by me sending too many requests. So I’ve hit my DataStore quota? Appearantly not, since if I save myself right after, it’ll work perfectly fine (even though it consists of multiple SetAsync calls too). It is consistent for that specific person and his specific savegame. See also this screenshot:
So it doesn’t seem like I’ve actually hit the quota.
See also this screenshot, his attempted save (failed at the second SetAsync of the four total). It consistently fails on this SetAsync call for some reason. The amount of key and value characters are clearly below the maximum and I’ve tried reducing the SetAsync value length too.
Weird thing is, I’m completely unaffected myself. Quite some other users are apparently unaffected too (as the volume of complaints isn’t that high). The only thing that differs in the savegames in this aspect is the userid in the key. So I tried “hijacking” his pool (in-game building plot), making it mine, then saving it myself. Surprise, it worked with my own userid! This did cause a SetAsync to a completely fresh, never written before key, though, so that could be related. Whenever “hijacking” the owner of the pool back to the original owner, he was also able to save it again. The difference is that the revision index in the key (the r91 bit in the key in the above screenshot) got incremented by one (this allows the game to fall back in case saving fails halfway though). Causes a fresh new write again.
Somehow it broke again after he rejoined (loading kept working). After re-doing the hijack-loop, it managed to work again. Another rejoin, now he is able to save it after loading without me “hijacking” it first for some reason.
Something weird is going on I assume, but it’s seriously affecting my game at the moment.
I haven’t updated the game in question in nearly two weeks (except now to add some additional logging), thus I don’t think one of my changes caused it to start acting up.
I can confirm something similar has happened to my friend Polymorphic, all of a sudden he is randomly getting “ProvisionedThroughputExceeded” errors, whereas in the past (he hasn’t updated the place in over 2 weeks) this would never happen.
DataStore only lets you store 64998 characters, so seems that you are storing the data in multiple keys. Can you make it print each key that is being written to, as well as the number of characters being written to?
Place #6264626, it uses the following code to split the whole thing into multiple keys (don’t trip on the ancient mess):
The value of each key-value pair is limited to 50k characters, in the initial post I reduced it to 45k characters to check if I somehow hit the limit anyway, but I’ve reverted that change again now.
[code]-- Saves a serialized pool (json), set ident to nil to save as a new pool.
– Returns ident, true if succesful.
_G.SavePool = function(player, json, ident, revision, name, money)
ident = ident or _G.GetIdent(player);
if (ident == nil) then
return 0, false;
end
if (json:len() > 50000 * 15 - 1) then
print(“MaxSize Exceeded.”);
return 0, false;
end
print("Ident", ident);
local userId = player.userId;
local latestKey = "none";
local lastLen = 0;
local lastJson = "";
local ok, err = pcall(function()
local chunk = 0;
local totalChunks = math.ceil(json:len() / 50000);
for i = 1, json:len(), 50000 do
Workspace.Events.ProgressEvent:FireClient(player, "Saving...", "Chunk " .. (chunk + 1) .. "/" .. totalChunks);
local subjson = json:sub(i, i + 50000 - 1);
latestKey = "u" ..userId .. "_save" .. ident .. "_r" .. revision .. "_chunk" .. chunk;
lastLen = #subjson;
lastJson = subjson;
print("Saving into key: [" .. latestKey .. "] value len " .. lastLen);
saveGamesDS:SetAsync(latestKey, subjson);
chunk = chunk + 1;
end
_G.UpdateMetadata(player, ident, name, money, chunk, revision);
end);
if (not ok) then
print("Save err " .. err .. "--- key: [" .. latestKey .. "] value len " .. lastLen);
print(lastJson);
print("Save err " .. err .. "--- key: [" .. latestKey .. "] value len " .. lastLen);
end
return ident, ok;
end;
[/code]
Prints
Ident 1
Saving into key: [u1741242_save1_r93_chunk0] value len 50000
Saving into key: [u1741242_save1_r93_chunk1] value len 50000
Saving into key: [u1741242_save1_r93_chunk2] value len 18383
for me in the console (same pool as the one the broken user had in that image, but copied to me). This technique has always been used by me, anyway. “Saving into key” messages were added just for illustrating how it’s all saved.
This happened to me once when I was deleting a hacker’s save file. I deleted his save file again and it worked perfectly fine. Since it’s impossible for me to break the datastore limit request in my game in Play Solo mode, I don’t think it’s on my end.
I was using UpdateAsync and this is what happened:
An error occurred: HTTP 429 (HTTP/1.1 429 ProvisionedThroughputExceeded)
I can assure you that empty savefiles in my game do not exceed 65k characters.
Even though this error is thrown, it appears that some save attempts [do] succeed. No idea if this is always the case though, since my script simply stops saving after an error.
This seems fixed now, I can’t tell for sure though.
At least a single person claimed it works again after it failing for days and I’ve received no new complaints.