Bindtoclose or Coroutine is not working

Hello,
It seems as though my datastoring coroutine is not working at all. See this video below.

Code:

local datastore = game:GetService("DataStoreService")
local moneystore = datastore:GetDataStore("Stats")

game.Players.PlayerAdded:Connect(function(p)
	local leader = Instance.new("IntValue",p)
	leader.Name = "leaderstats"
	local mon = Instance.new("NumberValue",leader)
	mon.Name = "Money"
	local so = Instance.new("StringValue",leader)
	so.Name = "Job"
	local ren = Instance.new("NumberValue",leader)
	ren.Name = "Reputation"
	local gor = moneystore:GetAsync(p.UserId)
	if gor~=nil then
		mon.Value = gor[1]
		so.Value = gor[2]
		ren.Value = gor[3]
	else
		gor = {mon.Value,so.Value,ren.Value}
	end
	for i,v in pairs(script.Notice:GetChildren()) do
		local sog = v:Clone()
		sog.Parent = p
	end
end)

local function save(v)
	coroutine.wrap(function()
		print('sag')
		local success, response
		local tries = 0
		local saveData = {v.leaderstats.Money.Value,v.leaderstats.Job.Value,v.leaderstats.Reputation.Value}

		success, response = pcall(moneystore.SetAsync, moneystore, v.UserId, saveData)

		repeat
			wait(7)
			success, response = pcall(moneystore.SetAsync, moneystore, v.UserId, saveData)
			tries += 1
		until not success or tries < 3 
	end)()
end


game.Players.PlayerRemoving:Connect(function(p)
	
end)

game:BindToClose(function()
	for i,v in pairs(game.Players:GetPlayers()) do
		save(v)
	end
end)

Note: I removed the playerremoved code to test out if bindtoclose actually worked at all. It will print out something when the coroutine is run.

- Br, iSyriux

Hello,
@MrNicNac, I would personally like to invite you to assist me on this seemingly impossible endeavor.

1 Like

Hello,
Unfortunately, I have not found a solution as of yet. I am still struggling with this solution, and any valid help is appreciated.

Hello,
Upon further testing, it has been revealed that BindtoClose() actually does work, however, the coroutine function that is used inside it does not run, but runs in PlayerRemoved?
What type of behaviour is this?
I further descend into the rabbithole of frustrating bugs and I have so far recieved little to no help.

I’ve investigated your issue and recapped on the previous thread. I’ve found no error. Check out the video below. I have also attached my place file that I demonstrated working.

There is something specific about your place file that is causing it not to work or the script you’ve shown isn’t the full picture.

I used the same code you did except I added save(p) back to the PlayerRemoving event.

dataStoreTest.rbxl (22.4 KB)

Hello,
Thanks for your miraculous reply.
Could you remove save(p) from the PlayerRemoving event to test out the functionality of BindtoClose alone, I feel like PlayerRemoving is the event that’s only working here.

Ah, I see your problem. Your coroutine is tricking you.

BindToShutdown waits until all functions return or 30 seconds have passed by.

When you use a coroutine, it becomes a parallel thread and your save() function instantly returns before saving is done.

Remove your coroutine from the save function.

Add it to PlayerRemoving manually
image

And let BindToClose run save() without the coroutine.

image

–

I did a test with only BindToClose

image

image

And it works now

image

I don’t think a parallel thread is actually required in the player removing block, but it would be in BindToClose event, as the save function will yield till its saved I believe? Which can take the time to save for all players above 30 seconds and resulting on dataloss.

1 Like

The coroutine does more than act as a parallel thread. In this case, we don’t have to worry because pcall is in play. Usually, you can use a coroutine to capture errors at runtime. In fact, coroutine.resume returns the error message of a broken code segment. So coroutines have two uses - not just acting as an asynchronous function scheduler.

It’s highly unlikely you will hit the 30 second mark. However, if that’s the case, we can run a “promise” system and wait until all saving has happened but initiate them as quickly as possible. This is common in languages like JavaScript or C#.

image

This will initiate all saving at around the same time and wait to close the server until either they are all saved or it has to be force closed after 30 seconds (Roblox limit).

Note: This only works because coroutines aren’t actual new CPU threads and are “Lua threads” that run asynchronously and not in parallel. Otherwise our “promisesReturned” variable would be forked and the memory address would be different and this wouldn’t work.

3 Likes

Hello,
Apologies for the lateness. My studio was lagging really badly and I had to restart.
It seems, through my trial testing your modified code, that Bindtoclose continues to not function correctly.

I notice your username is in the player list. Do not test DataStores with the “Play” button. Use the “Start” button to start a server.

Otherwise you will most likely have this issue and the data won’t save.

Here is it working with only BindToClose in use.

Hello,
The video you have shown does not show Player1 leaving and rejoining the game.
I am quite confused on how players with no UserId (I assume, since Player1 and Player2 aren’t real players, or their userid is dynamic and random each time.)

I’m not going to make a video again just to show you I’m leaving and joining. Since you’re not going to believe me, I’m not going to waste my time with this anymore. The place file is attached. Test it as you like. I’ve confirmed it is in working order.

dataStoreTest.rbxl (22.4 KB)

1 Like

Hello,
I am terribly sorry if you feel that I am wasting your time, but I simply am unable to fully understand what you are trying to convey here. Does this mean that BindToClose will not work when using the Play button, but will work in-game?

Hello,
In addition, script analysis shows that “saveData” is an unknown global value. Should I be concerned about this? The screenshots you have shown do not include this script analysis.

Your variable casing is wrong, the variable is savedata and is being referred as saveData, fairly simple problem.

But I want to add on that, I believe BindToClose only works when the game server is shutdown, so it probably won’t run together along with PlayerRemoving event. If you start a new server in studio, and do your datastore testing there it should work.

1 Like

Specifically, it’s a waste of my time when you think I’d go through all of this just to somehow lie to you and show you an edited video. I have attached the place file, test it for yourself for full proof.

To be clear, I do not know why BindToClose is a bit strange when you hit the “Stop” button. This has been an ongoing Roblox glitch/bug for 2 years now. Here is the related thread: BindToClose 100% Infinite Yield - Platform Feedback / Studio Bugs - Roblox Developer Forum

In short, it’s just not consistent when pressing Stop versus using an actual server. I wish I had more info on if there was a workaround, but simply there is no information on this and is an internal Roblox issue. Whenever data stores are involved, it’s common place for developers to test using a “local server” start rather than the Play button.

3 Likes