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:
1 parent
c781193ec9
commit
baa936e88d
3 files changed
+119
-8
No files matched your search
@@ -218,6 +218,31 @@ def main() -> int:
|
||||
check("unreachable peers are reported as such",
|
||||
"could not reach peer" in (r["tried"] or ""), r["detail"])
|
||||
|
||||
print("\nsystemic failures do not burn the ladder")
|
||||
# slskd timing out says nothing about any particular file, so walking the
|
||||
# whole list to learn it once is waste -- and it is what took a real
|
||||
# request down: five enqueues in twenty-five seconds during one slskd stall.
|
||||
fake4 = FakeSlskd(per_query={"Chicago": [
|
||||
peer(f"p{i}", r"x\Michael Jackson\Xscape\Chicago.flac") for i in range(8)]})
|
||||
|
||||
class Timeouts(FakeSlskd):
|
||||
async def post(self, url, json=None):
|
||||
if url != "/api/v0/searches":
|
||||
raise RuntimeError("The wait timed out after 5000 milliseconds")
|
||||
return await FakeSlskd.post(self, url, json=json)
|
||||
|
||||
t = Timeouts(per_query=fake4.per_query)
|
||||
app.slskd_client = t
|
||||
make_job("j5", "Michael Jackson", "Chicago")
|
||||
asyncio.run(app.pick_and_enqueue("j5", "Michael Jackson", "Chicago"))
|
||||
r = job_row("j5")
|
||||
check("stops after SYSTEMIC_LIMIT instead of walking the whole list",
|
||||
r["attempts"] == app.SYSTEMIC_LIMIT, r["attempts"])
|
||||
left = json.loads(r["candidates"] or "[]")
|
||||
check("untried candidates are preserved for a retry", len(left) > 0, len(left))
|
||||
check("the message says a retry will resume",
|
||||
"retry resumes" in (r["detail"] or ""), r["detail"])
|
||||
|
||||
print("\nempty results")
|
||||
fake3 = FakeSlskd(per_query={})
|
||||
app.slskd_client = fake3
|
||||
|
||||
Reference in new issue
Block a user