DataStore request was added to queue. If request queue fills, further requests will be dropped

I thought I was experienced with DataStores, turns out I’m not. I thought I did it the proper way, yet I’m already get these messages which I believe will lead to data loss.

Script:

local dataStoreService = game:GetService("DataStoreService")
local playerService = game:GetService("Players")
local replicatedStorage = game:GetService("ReplicatedStorage")
local serverStorage = game:GetService("ServerStorage")

-- // Main Data Store
local store = dataStoreService:GetDataStore("MainDataStore")
local DEFAULT_DATA = {
	taps = 0,
	gems = 0,
	rebirths = 0,
	DataID = 0
}

-- // Functions

local function loadData(client)
	local success,data,err
	local attempts = 0
	
	while not success do
		success,err = pcall(function()
			data = store:GetAsync(client.UserId)
		end)
		if not success then
			attempts = attempts + 1
			warn("Failed to load " .. client.Name .. "'s data. Attempt #" .. tostring(attempts) .. ". Error: " .. err)
			wait(5)
		end 
	end
	
	if data then
		client.leaderstats.Taps.Value = data.taps
		client.leaderstats.Gems.Value = data.gems
		client.leaderstats.Rebirths.Value = data.rebirths
		print("Loaded " .. client.Name.. "'s data successfully")
	end
end

local function saveData(client,auto)
	local success,err
	local attempts = 0
	
	while not success do
		success,err = pcall(function()
			local playerData = store:GetAsync(client.UserId) or DEFAULT_DATA
			store:UpdateAsync(client.UserId,function(oldData)
				local previousData = oldData or DEFAULT_DATA
				if playerData.DataID == previousData.DataID then
					playerData.taps = client.leaderstats.Taps.Value
					playerData.rebirths = client.leaderstats.Rebirths.Value
					playerData.gems = client.leaderstats.Gems.Value
					playerData.DataID = playerData.DataID + 1
					return playerData
				else
					return nil
				end
			end)
		end)
		if not success then
			attempts = attempts + 1
			warn("Failed to save " .. client.Name .. "'s data. Attempt #" .. tostring(attempts) .. ". Error: " .. err)
			wait(5)
		end 
	end
	
	if success then
		print("Saved " .. client.Name.. "'s data successfully")
	end
	
	if auto then
		
	end

end

playerService.PlayerAdded:Connect(function(client)
	local leaderstats = Instance.new("IntValue")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = client
	
	local taps = Instance.new("IntValue")
	taps.Name = "Taps"
	taps.Parent = leaderstats
	
	local rebirths = Instance.new("IntValue")
	rebirths.Name = "Rebirths"
	rebirths.Parent = leaderstats
	
	local gems = Instance.new("IntValue")
	gems.Name = "Gems"
	gems.Parent = leaderstats
	
	loadData(client)
end)

game.Players.PlayerRemoving:Connect(function(client)
	saveData(client)
end)

game:BindToClose(function()
	for _, client in ipairs(playerService:GetPlayers()) do
		coroutine.wrap(saveData)(client)
	end
	wait(2)
end)

I appreciate help!

This message means that you are sending too many requests to the DataStore. Try checking your script to see if it could be sending multiple save requests.

I know what the message means, I’m trying to know what to change to fix it.

Could it be because you’re calling both GetAsync & UpdateAsync together? That’s my only instance where you could get that error

The error is shown when game:BindToClose and game.Players.PlayerRemoving both events fire at the same time and call the saveData function, which in turn, attempts to write in a DataStore.

1 Like

How much times does this occur? Generally, if it happens at every save(test this in the live game), then it would be more of a problem.

Yeah, I thought that is what’s causing it, is there any reason I could prevent this, I mean I need the BindToClose function

(If for some reason that’s the issue) You could check if the player count is equal to 1 (Or 0 idk) in your PlayerRemoving event, then end the function early maybe so the rest of the code won’t run?

game.Players.PlayerRemoving:Connect(function(client)
    if #game.Players:GetPlayers() <= 1 then
        return
    end

	saveData(client)
end)

Don’t do that please.

One way to protect player data from being overwritten with data that wasn’t loaded, and also protect stuff like this, is to check if there’s a object inside the player saying the data was loaded. When saving data, it needs to be there, and if it is, destroy it and start saving.

Just an example:

--\\ This is pseudo-code!

game.Players.PlayerAdded:Connect(function(plr)
    --// leaderstats

    --// data is loaded

    local isLoaded = Instance.new("BookValue")
    isLoaded.Name = "IsLoaded"
    isLoaded.Value = true
    isLoaded.Parent = plr

    --// if data fails to load, :Destroy() it.

end)

local function SavePlayer(plr)
    if not (plr:FindFirstChild("IsLoaded") and plr.IsLoaded.Value) then return end
    plr.IsLoaded:Destroy()

    --// save data now.
end

I think you can also use Attributes instead.