DataStore Takes Up To 5 Minutes To Save

Hi,

I’ve recently released a small community game that involves a lot of data values that I save when a player leaves. The only problem is – the data takes 5 minutes to save. My code looks like this:

function module:SavePlayerData(player, fromShutdown)
	local repDataValues = RepDataValues:FindFirstChild(player.UserId .. "_Data")
	local servDataValues = SerDataValues:FindFirstChild(player.UserId)
	if not (repDataValues and servDataValues) then return end
	
	local playerTable = {}
	
	playerTable["NormalStats"] = getCurrentData(player)
	if playerTable["NormalStats"]["TimePlayed"] and player:FindFirstChild("timePlayed")  then
		playerTable["NormalStats"]["TimePlayed"] = playerTable["NormalStats"]["TimePlayed"]+ (os.time() - player:FindFirstChild("timePlayed").Value)/60
		TIME_COUNT:SetAsync(player.Name.."_"..player.UserId, math.floor(playerTable["NormalStats"]["TimePlayed"]))
	end
	if fromShutdown or game.ServerStorage:FindFirstChild("ShutDown") then print(player) playerTable["NormalStats"]["Combat"] = false end
	local inventoryData = game.ReplicatedStorage.Inventories:FindFirstChild(player.UserId .. "_Inventory")
	playerTable["Inventory"] = getCurrentInventory(player)
	playerTable["Upgrades"] = UpgradesFunction:Invoke(player, true)
	playerTable["Subclass"] = SubclassFunction:Invoke(player, true)
	
	
	spawn(function()
		local success = pcall(function()
			data:UpdateAsync(player.UserId, function(oldVal)
				if not playerTable["Upgrades"] then
					 playerTable["Upgrades"] = oldVal["Upgrades"]
				end
				return playerTable or oldVal
			end)
		end)
		if not success then
			local c = 0
			repeat
				c = c + 1
				success = pcall(function()
					data:UpdateAsync(player.UserId, function(oldVal)
						if not playerTable["Upgrades"] then
							 playerTable["Upgrades"] = oldVal["Upgrades"]
						end
						return playerTable or oldVal
					end)
				end)
				RUN.Heartbeat:Wait()
			until success or c > 30
		end
		
		-- clear the connections
		if eventTable[player.UserId .. "_InvConnect"] ~= nil then
			eventTable[player.UserId .. "_InvConnect"]:Disconnect()
			eventTable[player.UserId .. "_InvConnect"] = nil
		end
		
		repDataValues:Destroy()
		servDataValues:Destroy()
		inventoryData:Destroy()
	end)
end

Assuming I use this function on Players.PlayerRemoving, why does it seem like the data throttles? I don’t get any warnings in the output whenever a player leaves the game, and it doesn’t seem like I have any yields.

The weird part about this is that if you hop servers quickly, then you get some old data, but if you wait 5 minutes, then it seems like your data saves normally.

I would add an incremental auto-save, but the server size is 50 players and it would be saving a player’s data maybe every 3 seconds.

Something like this:

while true do
    for _, player in next, game:GetService"Players":GetPlayers() do
        module:UpdatePlayerData(player)
        wait(3)
    end
    wait(3)
end

Only thing I’m worried about is this causing extreme stress on the server due to this many requests… so I’m kind of stumped on what to do here.

One of the things that we did do to solve this problem momentarily was add an “auto-save” every time you complete a quest in the game, which occurs maybe every 20-30 minutes. This isn’t very reliable, though, because not everyone does quests very often, so it can’t be used as a reliable auto-save.

Does anyone know how I can fix this problem? It’s a very weird bug that I’ve never encountered before.

2 Likes

I’m really not sure what the problem is but I believe that you should auto save like every 30 seconds or so. If that’s too much you can try doing it in batches, where first half is half the players, second half is other half or something…

Also I’m not sure if you need to have a thread for repeatedly saving the player’s data until it succeeds. Try checking how many times updatasync fails and whether the buffer time on the next retry period is too little, possibly throttling the datastore. Using prints can give you a better idea of what’s going on in-game.

EDIT: I just noticed you used Heartbeat:Wait(). The wait period is possibly too low, try waiting up to a few seconds before repeating.

1 Like