OrderedDataStore yields infinitely when closing a game

I’m using Berezza’s method a storing data for my datastore module.
His method makes you name the datastore key on the timestamp where it was saved on. You create an ordereddatastore on the timestamp of the save. So when a player joins it gets the latest datastore if that datastore is corrupted to moves onto the last save and so on and so on until there are no more saves.

When using my module I have a common issue with :BindToClose() yielding forever. I’ve looked further into this and the yielding problem is the :Set() function. Using test prints I figured out that wthin the :Set() function the cause is OrderDataStore:SetAsync().

Module:

--[[
	DataStore(Player, DataStoreName) - Gives you a datastore
	DataStore:Set(data) - Gets data store.
	DataStore:Save() - Saves data store
	DataStore:Get(defaultValue, MaxRetries(3)) - Gets datastore and sets up a datastore. Use it when calling a datastore after.
	DataStore:SetBackupAsData(backupValue(number)) - Sets a backup as the current data
--]]


local DSS = game:GetService("DataStoreService")


local DataStoreMeta = {}

function DataStoreMeta:Set(data)
	local timeKey = os.time()
	-- Update cache data
	print("Got time stamp")
	self.Data = data
	print("Updated data")
	-- Update ordered data store data
	self.OrderedDataStore:SetAsync(timeKey, timeKey)
	print("Added ordered data store")
	-- Get datastore
	local DataStore = self.DataStore
	-- Set data store
	DataStore:SetAsync(timeKey, data)
	print("Added datastore value")
	return data
end

function DataStoreMeta:Get(defaultValue, maxRetries)
	if maxRetries==nil then -- Default retries
		maxRetries = 3
	end
	
	local pages = self.OrderedDataStore:GetSortedAsync(false, 10)
	local RecentSaves = pages:GetCurrentPage()
	local Key
	local Failed = false
	local ReTries = 0
	repeat
		if RecentSaves~=nil then
			for i,data in ipairs(RecentSaves) do
				if data~=nil then
					Key = data.value
					break
				end
			end
			if Key==nil then
				ReTries = ReTries+1
				local succ,err = pcall(function()
					RecentSaves = pages:AdvanceToNextPageAsync()
				end)
				if not succ then -- Is there another page to advance to?
					Failed = true -- End of page
				end
				wait()
			end
		end
	until Key~=nil or Failed or ReTries>=maxRetries
	if Key~=nil then -- If key isn't nil
		local DataStore = self.DataStore
		local data = DataStore:GetAsync(Key)
		if data~=nil then -- If the data isn't nil
			self.Data = data
			return data
		else -- Data is nil. Put default values in
			data = self:Set(defaultValue)
			self.Data = data
			return data
		end
	else -- No page found. Put default values in
		local data = self:Set(defaultValue)
		self.Data = data
		return data -- Update default values
	end
end

function DataStoreMeta:SetBackupAsData(backupnumber)
	local timeKey = os.time()
	local pages = self.OrderedDataStore:GetSortedAsync(false, math.huge)
	local chosenDataStore = pages[backupnumber]
	local data = self.DataStore:GetAsync(chosenDataStore.key)
	if data~=nil and chosenDataStore~=nil and chosenDataStore.value~=nil then -- Backup isn't nil
		self.DataStore:SetAsync(timeKey, data) -- Update current data to backup
		self.OrderedDataStore:SetAsync(timeKey, timeKey)
		return data
	else
		return false
	end
end



local module = {}
local DataStoreMetaTable = {}
DataStoreMetaTable.__index = DataStoreMeta
local DataStoreCaches = {}

local function DataStore(player, dataStorename)
	local dataStore = {}
	if DataStoreCaches[player] and DataStoreCaches[player][dataStorename]~=nil then -- Is there a cache for it?
		dataStore = DataStoreCaches[player][dataStorename]
	else 
		dataStore.Data = nil -- I'm gonna add a default value later
		dataStore.DataStore = DSS:GetDataStore(dataStorename, player.UserId) 
		dataStore.Player = {}
		dataStore.Player.Name = player.Name
		dataStore.Player.UserId = player.UserId
		dataStore.Player.Object = player
		dataStore.ServerData={}
		dataStore.ServerData.DataStoreName = dataStorename
		dataStore.OrderedDataStore = DSS:GetOrderedDataStore(dataStorename .. "_OrderedDataStore", player.UserId)
		if DataStoreCaches[player]==nil then -- Player cache table?
			DataStoreCaches[player]={}
		end
		DataStoreCaches[player][dataStorename] = dataStore -- Add cache
	end
	
	setmetatable(dataStore, DataStoreMetaTable) -- Turn datastore into a metatable
	
	local RemovingFired = false
	game:BindToClose(function() -- Game is shutting down
		repeat wait() until RemovingFired -- Allow game to close once data is save
	end)
	
	game:GetService("Players").PlayerRemoving:Connect(function(discconectUser)
		if player==discconectUser then
			print("User disconnected")
			dataStore:Set(dataStore.Data) -- Save the data
			print("Saved successfully")
			RemovingFired = true -- Once data is saved allow the game to close
		end
	end)
	
	return dataStore
end

return DataStore

The main problem is within the module the module but I provided the script just in case.

Datastore Handler:


local DataModule = require(game:GetService("ServerScriptService"):WaitForChild("CoreModules"):WaitForChild("DataStoreModule")) -- DataStore module

function playerAdded(plr)
	local dataStore = DataModule(plr, "Credits") --	Get user datastore
	print(tostring(dataStore.Data), "is before")
	dataStore:Get(0) -- Set up data store.
	print(tostring(dataStore.Data), "is after")
	local newModel = Instance.new("Model")
	newModel.Name = "leaderstats"
	newModel.Parent = plr
	local newValue = Instance.new("NumberValue")
	newValue.Name = "Credits"
	newValue.Value = dataStore.Data
	
	wait(1)
	
	dataStore:Set(dataStore.Data)
end

game:GetService("Players").PlayerAdded:Connect(playerAdded) -- Player been added?

if game:GetService("RunService"):IsStudio() then
	for _,plr in pairs(game:GetService("Players"):GetPlayers()) do
		playerAdded(plr)
	end
end

related to BindToClose 100% Infinite Yield ?

Please see the bug report linked by @The_PieDude. Closing this thread for that reason.

Also, if you intended to file this as a bug report, please let us know at @Community_Sage next time around instead of posting in a random category. (See rule 15.1 of the official rules) Posts must be properly categorized, and bug reports do not belong in Scripting Support.