Skip to content

Fix check_looping_torrents — read decypharr log file, not docker CLI - #6

Merged
DAdjadj merged 1 commit into
mainfrom
fix/looping-torrents-storm-detection
May 8, 2026
Merged

DAdjadj merged 1 commit into
mainfrom
fix/looping-torrents-storm-detection

Conversation

@DAdjadj

@DAdjadj DAdjadj commented May 8, 2026

Copy link
Copy Markdown
Owner

Summary

check_looping_torrents has been a silent no-op since at least the v1.1.6 pin (May 2026). It shelled out to subprocess.run(["docker", "logs", ...]) but the babysitarr container has only the docker socket mounted — no docker CLI binary. The resulting FileNotFoundError was caught by a bare except and the function returned 0 actions for months. Uncached-release retry storms (movies with no cached releases on Real-Debrid) ran unchecked until indexers gave out and the deleted-without-import email finally fired.

All-time action tally before this fix:

375 auto_reset_indexers
237 auto_clear_stuck
 95 auto_reset_prowlarr
 20 suspicious_deletion   <- email only, no fix
  0 blocklist_loop        <- the storm-stopper, never tripped

What changed

  • Read /decypharr-config/logs/decypharr.log directly (already mounted; same path check_symlink_loops uses).
  • New helpers _read_decypharr_log_tail and _count_processing_hashes at module scope, testable in isolation. Both window bounds so tests can anchor _now to a fixture timestamp. ANSI-strip defensively in the hash extractor (production logs put color escapes between Hash= and the hex value).
  • tests/test_log_parsing.py with 7 tests covering: hash extraction, ANSI handling, window filtering, fixture presence, end-to-end storm detection. Fixture tests/fixtures/decypharr_storm_sample.log is a real 6-hour capture of an active storm (Nymphomaniac Vol II, Remarkably Bright Creatures, Lorne, Tafiti/A Desert, etc).
  • CI: tests run on PRs and gate the build/deploy job via needs: test.

Test plan

  • python -m unittest discover -v tests — 7/7 pass on plex-server
  • Module imports cleanly with stubbed requests
  • Merge → CI runs tests → image builds → deploys
  • After deploy, check docker logs babysitarr for Found N looping torrents warnings on the next storm
  • Verify ACTION: blocklist_loop entries start appearing

🤖 Generated with Claude Code

The retry-storm detector has been a silent no-op since at least the
v1.1.6 pin: it shelled out to subprocess.run(["docker", "logs", ...])
but the babysitarr container has only the docker socket mounted, no
docker CLI. FileNotFoundError got swallowed by a bare `except`, the
function returned 0 actions for months, and uncached-release storms
ran unchecked until indexers gave out and emails fired about deleted
files.

Fix:
- Read /decypharr-config/logs/decypharr.log directly (already mounted;
  same path check_symlink_loops uses). New helpers
  `_read_decypharr_log_tail` and `_count_processing_hashes` are
  module-level and testable in isolation.
- Both bounds on the log window so tests can anchor `_now` to a
  fixture timestamp.
- ANSI-strip defensively in the hash extractor — the production log
  format puts color escapes between `Hash=` and the hex value.

Add tests/test_log_parsing.py with a real captured storm sample
(tests/fixtures/decypharr_storm_sample.log) so format drift fails CI
loudly. Wire the test job into the existing GitHub workflow as a
required `needs:` for build, and run it on PRs too.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@DAdjadj
DAdjadj merged commit 011d3c1 into main May 8, 2026
2 checks passed
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.

1 participant