How do custom signal objects handle errors?

I am making a signal-adjacent lua object for a project im working on and I have run into an issue with error handling. Under the hood there is a list of connected functions to run when the event is fired with a for loop. I want them to run as soon as possible (within the same frame), give me the correct output info while preventing an immediate error (within the first frame) to kill the thread that is running the functions to gurantee that an error in one callback doesn’t affect the others.

After testing all the different methods of doing this, I have not found any answer that satisfies all of these requirements.

  1. coroutine.wrap() - runs call back the fastest, survives but breaks the output and error logs
  2. coroutine.create() - same as coroutine.wrap()
  3. direct call - runs immediately, breaks thread
  4. task.spawn() - runs withing same frame but breaks parent thread
  5. task.defer() - parent thread survives but only runs roughly after task.wait() which is too late
  6. pcall() - runs fast, main thread survives + additional success and error info but has performance issues
  7. Bindable Event under the hood (fast spawn method I believe) - fast, survives but error info doesn’t inclue full stack and probably has performance issues

Is there any other way?

pcall is probably the safest bet. You could probably find a way to recover the full trace using Bindable Event. Maybe with a list of outstanding events somewhere, but you might still need pcall.