replaygain: Fix error handling for parallel runs

The parallelism strategy in #3478, in retrospect, used a pretty funky
way to deal with exceptions in the asynchronous work---since
`apply_async` has an `error_callback` parameter that's meant for exactly
this. The problem is that the wrapped function would correctly log the
exception *and then return `None`*, confusing any downstream code.
Instead of just adding `None`-awareness to the callback, let's just
avoid running the callback altogether in the case of an error.
This commit is contained in:
Adrian Sampson 2022-10-01 15:47:41 -07:00
parent 7f977079c3
commit 9803939a1c
No known key found for this signature in database
GPG key ID: BDB93AB409CC8705

View file

@ -1085,7 +1085,7 @@ class ExceptionWatcher(Thread):
try:
exc = self._queue.get_nowait()
self._callback()
raise exc[1].with_traceback(exc[2])
raise exc
except queue.Empty:
# No exceptions yet, loop back to check
# whether `_stopevent` is set
@ -1338,23 +1338,16 @@ class ReplayGainPlugin(BeetsPlugin):
def _apply(self, func, args, kwds, callback):
if self._has_pool():
def catch_exc(func, exc_queue, log):
"""Wrapper to catch raised exceptions in threads
def handle_exc(exc):
"""Handle exceptions in the async work.
"""
def wfunc(*args, **kwargs):
try:
return func(*args, **kwargs)
except ReplayGainError as e:
log.info(e.args[0]) # log non-fatal exceptions
except Exception:
exc_queue.put(sys.exc_info())
return wfunc
if isinstance(exc, ReplayGainError):
self._log.info(exc.args[0]) # Log non-fatal exceptions.
else:
self.exc_queue.put(exc)
# Wrap function and callback to catch exceptions
func = catch_exc(func, self.exc_queue, self._log)
callback = catch_exc(callback, self.exc_queue, self._log)
self.pool.apply_async(func, args, kwds, callback)
self.pool.apply_async(func, args, kwds, callback,
error_callback=handle_exc)
else:
callback(func(*args, **kwds))