From 0a2b3533f4b63abd0b902bf8e22bb56baad07950 Mon Sep 17 00:00:00 2001 From: JB Date: Fri, 28 Nov 2025 13:44:15 -0800 Subject: [PATCH] feat: Improve logging error handling in job processing to capture failures in stderr --- abogen/web/service.py | 8 ++++++-- tests/test_service.py | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/abogen/web/service.py b/abogen/web/service.py index 92f23b1..9da8e55 100644 --- a/abogen/web/service.py +++ b/abogen/web/service.py @@ -62,8 +62,12 @@ def _emit_job_log(job_id: str, level: str, message: str) -> None: try: _JOB_LOGGER.log(log_level, "[job %s] %s", job_id, message) except Exception: - # Logging failures should never disrupt job processing. - pass + # Logging failures should never disrupt job processing, but we should know about them. + try: + sys.stderr.write(f"Logging failed for job {job_id}: {message}\n") + traceback.print_exc(file=sys.stderr) + except Exception: + pass class JobStatus(str, Enum): diff --git a/tests/test_service.py b/tests/test_service.py index 18d68f5..9d7a19a 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -106,6 +106,45 @@ def test_job_add_log_emits_to_stream(tmp_path): assert job.logs[-1].message == "Test log line" +def test_job_add_log_handles_exception(tmp_path, capsys): + sample = tmp_path / "sample.txt" + sample.write_text("payload", encoding="utf-8") + + job = Job( + id="job-fail-test", + original_filename="sample.txt", + stored_path=sample, + language="a", + voice="af_alloy", + speed=1.0, + use_gpu=False, + subtitle_mode="Sentence", + output_format="wav", + save_mode="Save next to input file", + output_folder=tmp_path, + replace_single_newlines=False, + subtitle_format="srt", + created_at=time.time(), + ) + + # Mock the logger to raise an exception + original_log = _JOB_LOGGER.log + + def side_effect(*args, **kwargs): + raise RuntimeError("Logger exploded") + + _JOB_LOGGER.log = side_effect + + try: + job.add_log("This should trigger fallback", level="info") + finally: + _JOB_LOGGER.log = original_log + + captured = capsys.readouterr() + assert "Logging failed for job job-fail-test" in captured.err + assert "Logger exploded" in captured.err + + def test_retry_removes_failed_job(tmp_path): uploads = tmp_path / "uploads" outputs = tmp_path / "outputs"