Datastore Queue Overflow Help

Hello everyone, I have 4 Server Scripts that save 4 different IntValues in ReplicatedStorage. These scripts are in ServerScriptService and I don’t know why the Datastores aren’t working. I’m relatively new to Datastores, so I apologize if I don’t understand most of the things you are talking about. My game is also single player so I only put in 8 seconds of cooldown, even though it’s a 6 second limit.

All of the scripts are exactly the same, except for the variable changes at the top.
I also keep getting the error print “Uh oh there’s an error man Argument 2 missing or nil”.
I also have " DataStore request was added to queue. If request queue fills, further requests will be dropped. Try sending fewer requests.Key = Player_123123123" In Output.

One of the Datastore Server Scripts in ServerScriptService

local Upgrade = game.ReplicatedStorage.ClassFolder.ClassSaveNumberHolders.Juggernaut.JuggSaveValue
--Data Store
local DataStoreService = game:GetService("DataStoreService")
local classStore = DataStoreService:GetDataStore("ClassStore")

local players = game:GetService("Players")

game.Players.PlayerAdded:Connect(function()
	print("Upgrade 1 has "..Upgrade.Value)
end)

local function onShutDown()
	task.wait(8)
end

local function setUp(player)
	local userID = player.UserId
	local key = "Player_"..userID

	local data = classStore:GetAsync(key)

	local success, ret = pcall(classStore.GetAsync, classStore, key)

	if success then
		Upgrade.Value = ret or 0
	else
		print("Uh oh there's an error man "..ret)
	end

	repeat
		local success, ret = pcall(classStore.GetAsync, classStore, key)
	until success or not players:FindFirstChild(players.Name)

	Upgrade.Value = data or 0
end

local function save(player)
	local userID = player.UserId
	local key = "Player_"..userID

	classStore:SetAsync(key, Upgrade.Value)
	task.wait(8)
	local success, ret = pcall(classStore.SetAsync, classStore, key)

	if success then
		print("Yippee! The Points have been SAVED")
	else
		print("Uh oh there's an error man "..ret)
	end

	repeat
		local success, ret = pcall(classStore.SetAsync, classStore, key)
	until success or not players:FindFirstChild(players.Name)
end
game:BindToClose(onShutDown)
players.PlayerAdded:Connect(setUp)
players.PlayerRemoving:Connect(save)

Are all the scripts writing to the same key on the same DataStore? In that case, the 6 second cooldown is global, meaning it’s not per script but rather for the key. Have you tried using just one script to save all the data altogether every 6 seconds?

I haven’t because I have no idea how to. I’ve heard of tables, but I’m not entirely sure how to use them and the documentation was kind of hard to understand so I put if off to the side for now.

local classStore = ... -- your DataStore
local variable1 = ... -- your variable
local variable2 = ... -- your variable
-- and do that for all your variables

local function set()
	local data = {
		-- for example:
		Coins = variable1.Value,
		Level = variable2.Value
		--- and so on
	}

	classStore:SetAsync(key, data)
    -- don't be like me though, use a pcall
end

You would use a table to store a player’s data, this way making it, not also faster and efficient, but in a more organized way.

I’m a bit confused, for my “local data = …” I put “classStore:GetAsync(key)”
But you put the variables/table that I would use.
What’s the difference? Or am I missing something?

You said you’re trying to store four IntValues. I am simply using four variables to refer to those IntValues, so then I can create a table, which stores their Value, and use SetAsync() to set the data (the table) for the key (player).

Oh I see, I think I understand. The only thing is, do I have to loop through the table or is the table like an array of some sort?
Here’s what I changed in the local functions

local function setUp(player)
	local userID = player.UserId
	local key = "Player_"..userID
	
	local data = classStore:GetAsync(key)

	local success, ret = pcall(classStore.GetAsync, classStore, key)

	if success then
		UpgradeJ.Value = ret or 0
		UpgradeS.Value = ret or 0
		UpgradeN.Value = ret or 0
	else
		print("Uh oh there's an error man "..ret)
	end

	repeat
		local success, ret = pcall(classStore.GetAsync, classStore, key)
	until success or not players:FindFirstChild(players.Name)

	UpgradeJ.Value = data or 0
	UpgradeS.Value = data or 0
	UpgradeN.Value = data or 0
end

local function save(player)
	local userID = player.UserId
	local key = "Player_"..userID
	local upgrades = {
		UpgradeJ.Value,
		UpgradeN.Value,
		UpgradeS.Value
	}

	classStore:SetAsync(key, upgrades)
	task.wait(8)
	local success, ret = pcall(classStore.SetAsync, classStore, key)

	if success then
		print("Yippee! The Points have been SAVED")
	else
		print("Uh oh there's an error man "..ret)
	end

	repeat
		local success, ret = pcall(classStore.SetAsync, classStore, key)
	until success or not players:FindFirstChild(players.Name)
end

Within your code, you aren’t telling the repeat loop to yield, because of that you are sending too many requests at a time causing your Data to be sent into a queue.
You should Instead check if the pcall() wasn’t successful within the Loop and yield if that result is true.

Isn’t this what part of the function does though? Or am I getting this confused?

local success, ret = pcall(classStore.SetAsync, classStore, key)

	if success then
		print("Yippee! The Points have been SAVED")
	else
		print("Uh oh there's an error man "..ret)
	end

	repeat
		local success, ret = pcall(classStore.SetAsync, classStore, key)
	until success or not players:FindFirstChild(players.Name)

This part specifically.

I dont exactly see the purpose of you having the pcall() outside of the loop if you are going to do the same thing within the loop, that may be causing the Queue as well.

I see, and you’re saying it doesn’t end until the pcall is successful, which is making an overflow of queues because it isn’t always successful?

It Depends,

After looking at your code, you appear to be sending 2 Requests to Get Data under the same Data store, under the Same Key.

If its the repeat causing the issue, I simple fix would be:

repeat
	local success, ret = pcall(classStore.SetAsync, classStore, key)
    if not Success then -- if GetAsync() fails (Happens from time to time)
        task.wait(2) -- Time to wait until the code retires
    end
until success or not players:FindFirstChild(players.Name)

However, this can have the loop send too many requests for one player, so you should have a Variable to track the Attempts:

local Attempts = 1 -- to keep track of the Attempts
repeat
	local success, ret = pcall(classStore.SetAsync, classStore, key)
        Attempts += 1 -- Adds Attempt
    if not Success then -- if GetAsync() fails (Happens from time to time)
        task.wait(2) -- Time to wait until the code retires
    end
until success or not players:FindFirstChild(players.Name) or Attempts > 3

However if its the pcall() before the loop, try removing it, Since you are doing the exact same thing within the loop, I don’t see the purpose of it being there.

local success, ret -- These are important to get the Data from the loop.
local Attempts = 1

repeat
	success, ret = pcall(classStore.SetAsync, classStore, key) -- Uses Variables outside the scope to send Data to them
        Attempts += 1 
    if not Success then
        task.wait(2)
    end
until success or not players:FindFirstChild(players.Name) or Attempts > 3

if success then -- accessible outside the scope

Ah, I think the reason why I have two of these is because the “.GetAsync” part might fail. I’ll also be honest, I got most of this code from one of the DevForum tutorials since I didn’t understand Datastores.
I also just ran my game and it seems to be working, but lags behind a bit before stopping the game.

That may be due to the BindToClose function you have.
BindToClose fires when the Server is closing, and within your BindToClose, you are are telling the code to yield for 8 seconds.

BindToClose for DataStores is usually meant to save data as a emergency in case of shutdowns for Save Fails

Oh so, if I just change that to 6 seconds, it should be fine. right?..

Should be, However you should use it for this purpose rather than for yielding:

Oh I see, well thank you for helping me! And Thank you too @Vanniris !

1 Like

I’d like to point out that this isn’t using GetAsync and it’s also missing a value parameter if it’s truly meant to be SetAsync

1 Like

it isn’t my code, ask him about it, but thanks for pointing that out.

1 Like

No need for task.wait() here. SetAsync itself yields the script.
image

When you send a request, the script will yield, and only continue when the method returns a value. In that case, corresponding variables will be assigned, so doing if not success then task.wait() end does practically nothing if it’s successful**. Otherwise yeah, you can try again later.