Threading Best Practices

Best practices when dealing with background threads and tasks

Streamer.bot provides an isolated AppDomain sandbox that catches and logs runtime errors originating from C# CPH scripts.

While standard synchronous code, wrapped execution paths, and standard Task operations are fully caught, unhandled exceptions on raw background threads can bypass exception barriers and crash the host application.

To ensure your code and custom actions remain stable, follow these standard patterns when working with async operations or multi-threading:

Always use async Task when declaring asynchronous helper methods

When an exception occurs in an async Task method, the exception is encapsulated inside the returned Task object, allowing Streamer.bot to log the failure cleanly.

Conversely, exceptions inside an async void method bypass task scheduling and bubble directly to the unhandled thread pool context.

❌ Incorrect
// BAD: Exceptions thrown here escape the application exception barrier!
private async void PerformBackgroundProcess() {
    await Task.Delay(1000);
    throw new Exception("This will crash the process!");
}
✅ Correct
// GOOD: The returned Task allows Streamer.bot to catch and log errors safely.
private async Task PerformBackgroundProcessAsync() {
    await Task.Delay(1000);
    // Any exceptions here will be caught and output to the CPH log
    throw new Exception("This will be logged safely.");
}

Avoid spinning up raw system threads using new Thread()

Instead, use Task.Run() or Task.Factory.StartNew()

❌ Incorrect
// BAD: Dedicated threads run outside the CPH execution frame.
new Thread(() =>{
    // Unhandled errors here cannot be intercepted by the host app
    DoWork();
}).Start();
✅ Correct
// GOOD: Tasks are managed by the TaskScheduler and unobserved errors are safely caught.
Task.Run(() =>{
    DoWork();
});

When importing external pre-compiled libraries into your CPH scripts:

  • Static source inspection cannot scan pre-compiled assembly binaries (.dll files).
  • Ensure any third-party library you use handles its own internal background thread exceptions.
  • Wrap library initialization and method calls inside try / catch blocks where appropriate within your script's Execute() or Init() methods.