Skip to content

Commit 58bbb93

Browse files
chrisguidryclaude
andcommitted
Log errors on retry attempts too
Same fix as the Perpetual error logging — Retry.handle_failure() was returning True and swallowing the exception. Now each retry attempt logs the error at ERROR level with the full traceback before the reschedule info line. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent af039e5 commit 58bbb93

File tree

2 files changed

+35
-0
lines changed

2 files changed

+35
-0
lines changed

src/docket/dependencies/_retry.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ async def handle_failure(self, execution: Execution, outcome: TaskOutcome) -> bo
8989

9090
worker = current_worker.get()
9191
TASKS_RETRIED.add(1, {**worker.labels(), **execution.general_labels()})
92+
93+
if outcome.exception:
94+
logger.error(
95+
"↩ [%s] %s",
96+
format_duration(outcome.duration.total_seconds()),
97+
execution.call_repr(),
98+
exc_info=outcome.exception,
99+
)
100+
92101
logger.info(
93102
"↫ [%s] %s",
94103
format_duration(outcome.duration.total_seconds()),

tests/fundamentals/test_retries.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Tests for error handling and retry strategies."""
22

3+
import logging
34
from datetime import datetime, timedelta
45
from typing import Callable
56
from unittest.mock import AsyncMock
@@ -28,6 +29,31 @@ async def test_errors_are_logged(
2829
assert "Faily McFailerson" in caplog.text
2930

3031

32+
async def test_retry_errors_are_logged(
33+
docket: Docket, worker: Worker, caplog: pytest.LogCaptureFixture
34+
):
35+
"""Each retry attempt logs the exception at ERROR level."""
36+
calls = 0
37+
38+
async def the_task(retry: Retry = Retry(attempts=3)):
39+
nonlocal calls
40+
calls += 1
41+
raise ValueError("attempt failed")
42+
43+
await docket.add(the_task)()
44+
45+
with caplog.at_level(logging.ERROR):
46+
await worker.run_until_finished()
47+
48+
assert calls == 3
49+
error_records = [r for r in caplog.records if r.levelno == logging.ERROR]
50+
assert any(
51+
"attempt failed" in r.getMessage()
52+
or (r.exc_info and "attempt failed" in str(r.exc_info[1]))
53+
for r in error_records
54+
)
55+
56+
3157
async def test_supports_simple_linear_retries(
3258
docket: Docket, worker: Worker, now: Callable[[], datetime]
3359
):

0 commit comments

Comments
 (0)