Stop the candidate ladder from hammering slskd through a stall

A live request for "Michael Jackson - Chicago" exercised both new paths
correctly -- the blocked artist name fell back to the bare title and found real
Xscape rips, and the ladder tried five peers instead of dying on the first --
and then failed anyway, with all five reporting a 500 from slskd.

slskd's own log shows why, and it is not the peers. Every timeout in the
preceding hour landed inside the single minute muse was enqueueing, and in the
same window slskd also failed to resolve three OTHER users' searches. Each
enqueue blocks about five seconds waiting on a peer message connection, so five
back-to-back attempts is twenty-five seconds of sustained pressure on one
subsystem. The ladder turned one bad moment into five spent candidates and a
dead request, and made slskd worse for everyone else while doing it.

Attempts are now spaced by MUSE_ATTEMPT_BACKOFF. Failures are classified: "File
not shared" is about a file and still advances at once, while a timeout is about
slskd and, after MUSE_SYSTEMIC_LIMIT of them in a row, stops the walk and leaves
the untried candidates on the row. A retry resumes that ladder instead of
re-running a search whose answer has not changed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Aryan SinghandClaude Opus 5 committed 2026-09-02 11:51:10 -05:00
1 parent c781193ec9
commit baa936e88d
3 files changed
+119 -8

No files matched your search

+16
View File
@@ -258,6 +258,20 @@ A download that sits with no bytes for `MUSE_STALL_MINUTES` is abandoned the
same way, as is one slskd has forgotten about. Both used to leave the job in
`downloading` forever, with a cheerful pulsing dot and no log line.
**Not every failure is about the file.** "File not shared" concerns one file and
the next candidate is unaffected, so the ladder advances immediately. A timeout
says only that slskd could not talk to anyone just then, and the next candidate
would fail identically. Walking the whole list to learn that once is waste --
worse, it is harmful: each enqueue blocks about five seconds on a peer
connection, so eight back-to-back attempts is forty seconds of pressure on one
subsystem, and it takes other users' searches down with it. That is not
hypothetical; it is what a real request did.
So attempts are spaced by `MUSE_ATTEMPT_BACKOFF`, and after
`MUSE_SYSTEMIC_LIMIT` consecutive connection failures muse stops and **keeps the
untried candidates on the row**. Retrying then resumes the ladder where it
stopped rather than paying for a search whose answer has not changed.
## Review: when muse isn't sure
Picking a file and *trusting* it are different questions, so they use different
@@ -548,6 +562,8 @@ stat -c "%h" "/data/media/music/<Artist>/<Album> (<Year>)/<NN> - <Title>.flac"
| `MUSE_TITLE_FLOOR` | `0.5` | the title alone must clear this before the artist counts |
| `MUSE_CANDIDATES` | `8` | ranked candidates kept per request, for fallback |
| `MUSE_MAX_ATTEMPTS` | `5` | peers tried before a request is given up on |
| `MUSE_ATTEMPT_BACKOFF` | `4` | seconds between candidate attempts |
| `MUSE_SYSTEMIC_LIMIT` | `2` | consecutive connection failures before stopping |
| `MUSE_STALL_MINUTES` | `20` | a transfer moving no bytes for this long is abandoned |
| `MUSE_MAX_QUERIES` | `4` | rungs of the search ladder to try |
| `MUSE_MIN_CANDIDATES` | `3` | below this, escalate to the next query |