fix(background): keep the app alive when a background worker panics

Bug:
background_task joined the worker thread with .expect(...). Any panic
inside a background closure (decoding a malformed file, an unexpected
None) was re-raised on the main thread and took the whole application
down, even though the worker's failure was already contained.

Reproduce:
1. Run an operation that executes in a background worker, e.g. loading
   or converting a deliberately corrupted file whose decoder panics.
2. Before: the process dies with the worker's panic message.
3. After: the command line shows "background task failed: <label> -
   <panic>" and the application keeps running.

Fix:
The worker closure is wrapped in catch_unwind; a panic is converted to
Message::BackgroundTaskFailed(context, message) delivered back to the
update loop and surfaced as a command-line error. Each call site passes
a context label naming the operation. A failed thread join (thread
aborted) is handled the same way instead of expect().
This commit is contained in:
Karim Jerbi committed 2026-09-30 19:15:49 +01:00
1 parent 2d6f4fcfdf
commit 3345b6453e
4 files changed
+115 -6

No files matched your search

+9
View File
@@ -3573,6 +3573,15 @@ pub enum Message {
/// Completion of a PDF/preview/print job performed outside the UI thread.
/// The boolean restores the Plot dialog after a preview.
BackgroundIoFinished(Result<String, String>, bool),
/// A background worker thread panicked or stopped without reporting a
/// result. Surfaced on the command line instead of taking the whole
/// process down with it.
BackgroundTaskFailed {
/// Which operation the worker was running (e.g. "STL export").
context: String,
/// Panic message (or channel-failure description) from the worker.
detail: String,
},
/// Send current layout to the system printer (via lp / lpr).
PrintToPrinter,
/// Callback from the async printer job.