mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-09-12 21:57:19 -04:00
CancelAsync read CurrentProcessable, which is lazy - _currentProcessable ??= Processes.Dequeue().Invoke() - so a book past its last step threw "Queue empty." on read, and the catch threw a second time interpolating CurrentProcessable.Name. Not a narrow race: every book waiting in the bad book dialog is in that state, because ProcessOneAsync reaches GetFailureActionAsync from its finally after the processable loop has drained. The faulted task then surfaced through the abort branch's Task.WhenAll, took QueueLoop out through its outer catch, and left the remaining books running with the progress bar still on screen. Test the _currentProcessable field instead, keep the property out of the catch message, and isolate each cancellation in CancelAllAsync so one book failing cannot abandon the rest of the list. Reading the field also stops the cancelling thread dequeuing from a non-thread-safe Queue<T> while the book's own loop reads it. Also drops the doubled <summary>/<param> left on CancelAllAsync by an earlier edit.