The web server holds several long-lived Mutexes in WebState (library,
downloader, watched, flags, positions, sessions, …). Every access used
.lock().unwrap(), so a single panic while any one was held would poison
it and turn EVERY subsequent request into a panic — one handler's bug
killing the whole server until restart.
New util::LockExt::lock_recover() acquires the guard but recovers the
inner data via PoisonError::into_inner() on poison. Our critical
sections are short and don't leave half-updated invariants, so the data
stays usable and a stuck request beats a stuck process. Applied to all
70 lock sites in web.rs.
Test poisons a mutex from a panicking thread and confirms lock_recover
still returns usable data. 96 pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>