From e46a269c313fbcd615240db5dc347d43e8db679c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Flis?= Date: Sat, 6 Jun 2026 13:49:02 +0200 Subject: [PATCH 1/2] fix: stop swallowing extraction errors in background task Remove the broad `except Exception` in ExtractorManager.__run_extractor. It only logged a one-line message and suppressed the exception, hiding the real traceback. Since extraction runs in a FastAPI BackgroundTask, the exception now propagates to Starlette and is logged with full traceback in the container logs, making failures diagnosable. The `finally` block still resets _active_extractor, so a crashed extraction no longer requires the except to avoid bricking the single-extractor lock. --- perfectframe/extractor_manager.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/perfectframe/extractor_manager.py b/perfectframe/extractor_manager.py index 41245ff..bec81de 100644 --- a/perfectframe/extractor_manager.py +++ b/perfectframe/extractor_manager.py @@ -44,8 +44,6 @@ def __run_extractor(cls, extractor: Extractor) -> None: """Run extraction process and clean after it's done.""" try: extractor.process() - except Exception: - logger.exception("Extraction failed with error") finally: with cls._lock: cls._active_extractor = None From ea8fd9a897f22566fb7a477cccd37dde27dc9772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Flis?= Date: Sat, 6 Jun 2026 13:53:46 +0200 Subject: [PATCH 2/2] test: assert extraction errors propagate and lock is released Update test_run_extractor to reflect the new contract: __run_extractor no longer swallows exceptions. The test now asserts the exception propagates (pytest.raises) and that the finally block still resets _active_extractor, so a crashed extraction does not leave the single-extractor lock stuck. --- tests/unit/extractor_manager_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/extractor_manager_test.py b/tests/unit/extractor_manager_test.py index 1e1edbc..1caff86 100644 --- a/tests/unit/extractor_manager_test.py +++ b/tests/unit/extractor_manager_test.py @@ -42,15 +42,15 @@ def test_run_extractor(mocker): mock_extractor.process.assert_called_once() -def test_run_extractor_logs_exception_on_failure(mocker, caplog): +def test_run_extractor_propagates_exception_and_resets_active(mocker): mock_extractor = mocker.MagicMock() mock_extractor.process.side_effect = RuntimeError("Test error") + ExtractorManager._active_extractor = ExtractorName.BEST_FRAMES - with caplog.at_level("ERROR"): + with pytest.raises(RuntimeError, match="Test error"): ExtractorManager._ExtractorManager__run_extractor(mock_extractor) mock_extractor.process.assert_called_once() - assert "Extraction failed with error" in caplog.text assert ExtractorManager._active_extractor is None