Coroutine.resume() bug while used in RemoteFunction & BindableFunction

bug
#1

I was excited to use the changed coroutine.yield on my project while I came across this coroutine issue while using it on RemoteFunction(OnServerInvoke).

ServerScript:


print("Server>> Initialized");
local remote = game.ReplicatedStorage.Request;

remote.OnServerInvoke = function(player)
	local currentThread = coroutine.running();
	print("Server>> Server invoked, Thread:",currentThread);
	coroutine.wrap(function()
		wait(1);
		coroutine.resume(currentThread, "Hello");
	end)();
	
	print("Server>> Server yielding, Thread:",currentThread);
	local yieldValue = coroutine.yield();
	print("Server>> Server yielded:", yieldValue,", Thread:",currentThread);
	return yieldValue;
end

Client Script


print("Client>> Hello world!");

local remote = game.ReplicatedStorage:WaitForChild("Request");
local result;

print("Client>> Invoking server");
delay(2, function() print("Client>> Force print results:", result); end);
result = remote:InvokeServer();
print("Client>> Server results:",result);

Output


image


As you can see, server outputs yielded: Hello, but it doesn’t return the value to the invoked client and client is stuck yielding for the server’s return.

I’m not sure If I am doing something wrong or if this is a bug. Thanks in advance for reading.

yieldingIssue.rbxl (13.4 KB)

1 Like

#2

Wow, interesting find. I could reproduce this myself too. So using coroutine.yield within OnServerInvoke causes the return value to never get sent to the client, thus causing the client to yield indefinitely.

Perhaps this should be placed under Engine Bugs instead of Scripting Support?

4 Likes

#3

Looks like you cannot return a value to the client unless the coroutine created for OnServerInvoke was resumed by roblox’s thread scheduler:

Adding a wait() on line 15 makes the value to be correctly returned again:

14	print("Server>> Server yielded:", yieldValue,", Thread:",currentThread);
15	wait()
16	return yieldValue;
0 Likes

#4

Before the changes, my assumption is because roblox will take over threads that use any roblox asynchronous functions that yield the thread with the task manager. A problem however is that this effect is not applied beforehand to new threads. A simple example would be using coroutine.yield() before a wait() call and then one after. The second yield will output like a wait() call because of the task managing process. This is most likely a result of the task manager not being able to manage the process’s yield correctly because, as mentioned above, a wait call (which again asserts the thread into the task managing process) will fix the issue. It might have something to do with the change not functioning correctly for these functions in specific.

0 Likes

#5

This behavior has been fixed a while ago.

Code such as this:

local t = coroutine.running()
coroutine.wrap(function()
	while coroutine.status(t) ~= "dead" do
		coroutine.resume(t, "Manual resume")
		wait(1)
	end
end)()
print(coroutine.yield())
print(wait())
print(coroutine.yield())

now prints:

--> Manual resume
--> 0.033623059261913 938.04577054351
--> Manual resume
0 Likes

#6

As said above

0 Likes

#7

I was able to reproduce this with the following code

local bindable = Instance.new("BindableFunction")

function bindable.OnInvoke()
	print("Invoked")
	local thread = coroutine.running()
	spawn(function ()
		print("Thread resuming")
		coroutine.resume(thread, "Howdy")
	end)
	print("Thread yielding")
	local result = coroutine.yield()
	print("Thread resumed")
	return result
end

local result

delay(1, function ()
	print("Force print:", result)
end)

print("Invoke")
result = bindable:Invoke()

print("Print:", result)

I have a feeling I know what is going on. I’ll verify this now and hopefully have a fix for this soon.

3 Likes

RemoteFunction InvokeClient -> OnClientInvoke does not return when using coroutine.yield/resume
After resuming a Wait() thread, wait() no longer functions properly
#8

This seems to be unrelated to coroutine.yield and instead, it is related to coroutine.resume. You can repro this by replacing the call to yield in my example with wait(1e5).

I will continue looking into this.

2 Likes

#9

Any updates on this issue may I ask?

0 Likes

#10

Has this been fixed yet? I seem to still be having this issue in the part of my project where I left off back when I first encountered it. Guess I’ll have to use another method in the meantime.

0 Likes