Skip to content

Claude/old unacked tasks monitor m04zo0#123

Merged
maximusunc merged 3 commits into
mainfrom
claude/old-unacked-tasks-monitor-m04zo0
Jul 13, 2026
Merged

Claude/old unacked tasks monitor m04zo0#123
maximusunc merged 3 commits into
mainfrom
claude/old-unacked-tasks-monitor-m04zo0

Conversation

@maximusunc

Copy link
Copy Markdown
Collaborator

No description provided.

claude added 2 commits July 13, 2026 12:11
A message that fails _build_task_context (malformed/legacy payload, bad
otel JSON, missing query_id) was being dropped from the poll loop without
being acked. Because get_task reads with the '>' cursor (never re-delivers
PEL entries) and reclaim_orphaned skips messages owned by a live/self
consumer, such a message stayed pending under the running worker forever --
invisible to reclaim and to the janitor (which only touches dead consumers).
This surfaced as the monitor's stuck_pending alert firing on very old unacked
tasks attributed to workers that are up and healthy.

Make an un-buildable message terminal instead of leaking it: ack + delete it
so it leaves the PEL and stream, and route it to finish_query with an ERROR
status when the parent query is still identifiable (mirroring
handle_task_failure). Applied at both build sites in get_tasks (the reclaim
path and the normal '>' delivery path); the latter previously wasn't even
wrapped in try/except, so a poison payload also crashed and restarted the
generator under the same consumer name.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F4MdXm6dPBjPkgEUBGqZr8
reclaim_orphaned and the monitor's janitor/poller invoked XPENDING via
broker_client.execute_command("XPENDING", ...). redis-py registers a response
callback on the XPENDING command name that only parses the *summary* form
(XPENDING key group); on the *extended* form (IDLE/start/end/count) it raises
IndexError. In reclaim_orphaned that exception was swallowed by the surrounding
try/except at DEBUG level, so reclaim silently returned [] for every stream --
orphaned pending messages left by crashed/restarted workers were never
XCLAIMed and accumulated forever under dead consumers, invisible to the live
workers (which only read new '>' messages) but visible to the monitor's XINFO
scan, tripping stuck_pending on healthy workers.

The same mistake affected the summary-form callers, which received the parsed
dict but checked for a list/tuple:

- janitor._trim_stream read pending as 0 and computed the trim MINID from
  last-delivered-id, which trims away *unacked* pending messages (their ids are
  <= last-delivered-id) -- deleting live work from the stream and leaving
  dangling PEL entries. This is very likely how the orphans were created.
- janitor.reclaim_dead_consumers (the admin cleanup) hit the same extended-form
  crash and found no messages to drop.
- poller._collect_streams always reported per-stream pending as 0 on the
  dashboard.

Switch all sites to redis-py's typed helpers (xpending_range / xpending) and
parse the dict results. Verified against a real Redis: reclaim now claims a
present orphan and clears a dangling PEL entry (message already deleted by the
old trim). Adds tests/unit/test_reclaim.py, which reproduces the swallowed-error
regression via fakeredis (it shares redis-py's XPENDING callback).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F4MdXm6dPBjPkgEUBGqZr8
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 35.00000% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 51.03%. Comparing base (73a47c6) to head (a5d0a9e).
⚠️ Report is 13 commits behind head on main.

Files with missing lines Patch % Lines
workers/monitor/janitor.py 0.00% 11 Missing ⚠️
shepherd_utils/shared.py 52.63% 9 Missing ⚠️
workers/monitor/poller.py 0.00% 4 Missing ⚠️
shepherd_utils/reclaim.py 66.66% 0 Missing and 2 partials ⚠️
Files with missing lines Coverage Δ
shepherd_utils/reclaim.py 72.22% <66.66%> (+55.24%) ⬆️
workers/monitor/poller.py 15.69% <0.00%> (-0.10%) ⬇️
shepherd_utils/shared.py 71.89% <52.63%> (-0.51%) ⬇️
workers/monitor/janitor.py 17.73% <0.00%> (-0.20%) ⬇️

... and 3 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 761f30d...a5d0a9e. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@maximusunc
maximusunc merged commit 62070ff into main Jul 13, 2026
2 checks passed
@maximusunc
maximusunc deleted the claude/old-unacked-tasks-monitor-m04zo0 branch July 13, 2026 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants