-
-
Notifications
You must be signed in to change notification settings - Fork 7
Internal Exception Handling
Handling exceptions across thread boundaries is a complex task. This page explains how Squadron manages errors that occur within background workers and ensures they are propagated back to the caller.
When a task running in a worker fails, the following sequence of events occurs:
-
Detection: The
WorkerRunnerexecuting the task in the background thread catches the exception using atry-catchblock. -
Normalization: The caught error and stack trace are passed to
SquadronException.from().- If the error is already a
SquadronException, it is used as-is. - Otherwise, it is wrapped in a
WorkerException.
- If the error is already a
-
Serialization: The exception is converted into a
WorkerResponsewith an error status. TheWorkerResponse.wrapInPlace()method calls the exception'sserialize()method, which returns aListof platform-independent data. -
Transfer: The serialized list is sent back to the main thread via the platform's communication channel (e.g.,
SendPort.send()on Native orpostMessage()on Web). -
Deserialization: In the main thread, the
WorkerResponseis received. TheunwrapInPlace()method uses theExceptionManagerto deserialize the error list.- The
ExceptionManagerlooks at the first element of the list (the type identifier). - It invokes the corresponding registered deserializer.
- If no deserializer is registered for that type, it defaults to creating a
WorkerExceptionindicating a deserialization failure.
- The
-
Propagation: The reconstructed
SquadronExceptionis thrown by theWorker'ssend()orstream()method, allowing the caller to catch it using standardtry-catchblocks.
The ExceptionManager is the central registry for exception deserializers.
-
Built-in Exceptions: Squadron comes with several built-in exception types (e.g.,
CanceledException,TimeoutException,WorkerException). These are pre-registered in theExceptionManager. -
Custom Exceptions: As explained in the Exception Management page, custom exceptions should inherit from
WorkerExceptionand must be registered manually.
One of the challenges of multithreading is preserving stack traces. When an exception occurs in a worker:
- The worker captures the local stack trace.
- The stack trace is converted to a string during serialization.
- On the receiving side,
SquadronException.loadStackTrace()re-creates aStackTraceobject from this string. While this stack trace won't include the frames from the main thread that called the worker, it provides full visibility into what happened inside the worker's thread.
For streaming services, if an error occurs while the stream is being processed:
- The error is serialized and sent as a
WorkerResponse. - In the main thread, this response is added as an error event to the
StreamController. - The stream remains open unless
cancelOnErrorwas set totruewhen listening to the stream. - Subsequent items or errors can still be received until the stream is closed by the worker.
The WorkerRunner is the heart of the background thread. It ensures that no exception goes unhandled. Even if a service initialization fails or a command is not found, the WorkerRunner will catch the error and send it back through the channel, preventing the background thread from crashing silently.
💖 Support the project! Sponsor d-markey on GitHub.