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:
Never use async void
async Task when declaring asynchronous helper methodsWhen 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.
// 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!");
}
// 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.");
}
Prefer Task.Run() over new Thread()
Avoid spinning up raw system threads using new Thread()
Instead, use Task.Run() or Task.Factory.StartNew()
// BAD: Dedicated threads run outside the CPH execution frame.
new Thread(() =>{
// Unhandled errors here cannot be intercepted by the host app
DoWork();
}).Start();
// GOOD: Tasks are managed by the TaskScheduler and unobserved errors are safely caught.
Task.Run(() =>{
DoWork();
});
Handling Third-Party Assemblies
When importing external pre-compiled libraries into your CPH scripts:
- Static source inspection cannot scan pre-compiled assembly binaries (
.dllfiles). - Ensure any third-party library you use handles its own internal background thread exceptions.
- Wrap library initialization and method calls inside
try / catchblocks where appropriate within your script'sExecute()orInit()methods.