Canceling Coroutines Still Needs Work

Any updates on error coming from this code? (mentioned in the post too)

local Thread = task.spawn(function()
	workspace.ChildAdded:Wait()
end)

task.cancel(Thread)
Instance.new("Part", workspace)
1 Like

Fix for Wait/WaitForChild is implemented internally and should come in a future update (will be mentioned in the Release Notes 592+).

4 Likes

Threads cancelled while waiting on Wait/WaitForChild will no longer report an error.

2 Likes

Will they still stay in memory after cancelling them? Like keeping the coroutine in memory still until an object gets added or when the event gets triggered?

Or is just the error being removed? (Anyways I like that this was changed)

When task.cancel is called, only the reference to the thread object remains, parameters and target function reference/upvalues are cleared immediately.
Wait completion handler is still registered, but when itā€™s triggered, it will no longer attempt to resume the target that was cancelled.

Your suggestion for task cancellation callback is still a good idea to handle cases where connections have to be disconnected. Canā€™t do that automatically - functions passed to Connect are not owned by the thread and in some cases might be intended to remain connected.
But I have no timeline for when such feature will be added.

4 Likes

Iā€™m still encountering this error with more niche yielding methods like InvokeServer().

1 Like

Currently having a similar issue with hanging HTTP requests (run the code a few times)

local HttpService = game:GetService("HttpService")

HttpService.HttpEnabled = true

local function Request(timeout)
	HttpService:RequestAsync({ Url = "https://httpstat.us/504?sleep=" .. timeout * 1000 })
end

local function Timeout(timeout)
	local reqThread = task.spawn(Request, timeout)

	task.delay(timeout - 1, function()
		task.cancel(reqThread)
		print("Cancelled")
	end)
end

Timeout(2)

It seems to work fine with GetAsync but, from what Iā€™ve observed, this dead coroutine issue affects almost any method that yields & tries to resume in a thread that has been cancelled after the method yielded.

Is there any chance that this could be patched within the task & coroutine libraries (or internals of them), or maybe in the way that yielding is done? As it seems to be the root cause of the majority of these errors.
In other words, RequestAsync isnā€™t at fault here, imo.

Getting this error with remote functions. Was attempting to cancel a thread if client doesnā€™t respond and times out.

local ResponseReceived = false
local TimedOut = false
local time0 = time()
local thread = task.spawn(function()
  RemoteFunction:InvokeClient(player)
  ResponseReceived = true
end)
while not ResponseReceived do
  task.wait()
  if time() - time0 > 10 then TimedOut = true break end
end
if TimedOut then
  task.cancel(thread) --successful
end

If the server doesnā€™t receive a response after 10 seconds, it cancels the thread with the InvokeClient, which works properly. HOWEVER, task.cancel seems to not actually kill the thread, since the InvokeClient() call continues to run. I know this because:

--client
RemoteFunction.OnClientInvoke = function()
  task.wait(20)
  return
end

The client waits 20 seconds to respond to the invocation. After 10 seconds, the server times out and supposedly ā€œcancelsā€ the thread. After another 10 seconds, the client returns and the server logs an error message:

cannot resume dead coroutine

This means that the invocation thread is being marked as ā€œdeadā€, but the thread clearly continues to run, since the invocation manages to receive the client response, even after it was ā€œcancelledā€