fix(plex): E30 review round 3 — a dead headshot breaks the Plex-failing streak, 410 held by a test
This commit is contained in:
@@ -244,7 +244,8 @@ def warm_portraits(db: Session, limit: int) -> dict:
|
|||||||
).tuples()
|
).tuples()
|
||||||
if thumb
|
if thumb
|
||||||
}
|
}
|
||||||
done = dead = plex_failed = down = 0 # `down` counts in a row, `plex_failed` in all
|
# `down` counts Plex failing in a row (any answer from Plex breaks it), `plex_failed` in all
|
||||||
|
done = dead = plex_failed = down = 0
|
||||||
with plex:
|
with plex:
|
||||||
for pid in people_by_credits(db, "portrait", None):
|
for pid in people_by_credits(db, "portrait", None):
|
||||||
if done + dead >= limit or down >= _PLEX_DOWN_AFTER:
|
if done + dead >= limit or down >= _PLEX_DOWN_AFTER:
|
||||||
@@ -264,7 +265,7 @@ def warm_portraits(db: Session, limit: int) -> dict:
|
|||||||
# Plex failing, which must neither mark the file nor keep the run going.
|
# Plex failing, which must neither mark the file nor keep the run going.
|
||||||
cause = exc.__cause__
|
cause = exc.__cause__
|
||||||
if isinstance(cause, httpx.HTTPStatusError) and cause.response.status_code in _DEAD:
|
if isinstance(cause, httpx.HTTPStatusError) and cause.response.status_code in _DEAD:
|
||||||
dead += 1
|
dead, down = dead + 1, 0 # Plex answered: it is up, the streak is broken
|
||||||
imgcache.mark_miss(key)
|
imgcache.mark_miss(key)
|
||||||
else:
|
else:
|
||||||
plex_failed, down = plex_failed + 1, down + 1
|
plex_failed, down = plex_failed + 1, down + 1
|
||||||
|
|||||||
@@ -117,13 +117,15 @@ def test_the_batch_stores_the_hungarian_biography(db):
|
|||||||
|
|
||||||
class _Plex:
|
class _Plex:
|
||||||
"""A PlexClient stand-in. `down`: urls Plex does not answer for (True: none); `dead`: urls Plex
|
"""A PlexClient stand-in. `down`: urls Plex does not answer for (True: none); `dead`: urls Plex
|
||||||
answers "not found" for (a dead CDN file); `status`: an error status Plex answers every url with."""
|
answers `gone` for (a dead CDN file: "not found"); `status`: an error status Plex answers every
|
||||||
|
other url with."""
|
||||||
|
|
||||||
def __init__(self, down=False, dead=(), status=None):
|
def __init__(self, down=False, dead=(), status=None, gone=404):
|
||||||
self.asked: list[tuple[str, int | None]] = []
|
self.asked: list[tuple[str, int | None]] = []
|
||||||
self.down = down
|
self.down = down
|
||||||
self.dead = set(dead)
|
self.dead = set(dead)
|
||||||
self.status = status
|
self.status = status
|
||||||
|
self.gone = gone
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
return self
|
||||||
@@ -135,7 +137,7 @@ class _Plex:
|
|||||||
self.asked.append((url, width))
|
self.asked.append((url, width))
|
||||||
if self.down is True or (self.down and url in self.down):
|
if self.down is True or (self.down and url in self.down):
|
||||||
raise plex_people.PlexError("down") from httpx.ConnectError("refused")
|
raise plex_people.PlexError("down") from httpx.ConnectError("refused")
|
||||||
code = 404 if url in self.dead else self.status
|
code = self.gone if url in self.dead else self.status
|
||||||
if code:
|
if code:
|
||||||
req = httpx.Request("GET", url)
|
req = httpx.Request("GET", url)
|
||||||
status = httpx.HTTPStatusError(
|
status = httpx.HTTPStatusError(
|
||||||
@@ -236,13 +238,23 @@ def test_plex_failing_between_successes_does_not_end_the_run(db, cache_dir, plex
|
|||||||
assert plex_people.warm_portraits(db, 100) == {"cached": 4, "failed": 4}
|
assert plex_people.warm_portraits(db, 100) == {"cached": 4, "failed": 4}
|
||||||
|
|
||||||
|
|
||||||
def test_dead_headshots_are_left_alone_and_the_rest_still_land(db, cache_dir, plex_on):
|
def test_plex_failing_between_dead_files_does_not_end_the_run(db, cache_dir, plex_on):
|
||||||
|
_faces(db, 8)
|
||||||
|
plex_on["plex"] = _Plex( # down, dead, down, dead, …: Plex answers in between
|
||||||
|
down={CDN + f"{i}.jpg" for i in (0, 2, 4, 6)}, dead={CDN + f"{i}.jpg" for i in (1, 3, 5, 7)}
|
||||||
|
)
|
||||||
|
assert plex_people.warm_portraits(db, 100) == {"cached": 0, "failed": 8}
|
||||||
|
assert len(plex_on["plex"].asked) == 8
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("gone", [404, 410])
|
||||||
|
def test_dead_headshots_are_left_alone_and_the_rest_still_land(db, cache_dir, plex_on, gone):
|
||||||
_faces(db, 8)
|
_faces(db, 8)
|
||||||
dead = {CDN + f"{i}.jpg" for i in range(6)} # more dead files than any failure limit
|
dead = {CDN + f"{i}.jpg" for i in range(6)} # more dead files than any failure limit
|
||||||
plex_on["plex"] = _Plex(dead=dead)
|
plex_on["plex"] = _Plex(dead=dead, gone=gone)
|
||||||
assert plex_people.warm_portraits(db, 100) == {"cached": 2, "failed": 6}
|
assert plex_people.warm_portraits(db, 100) == {"cached": 2, "failed": 6}
|
||||||
|
|
||||||
plex_on["plex"] = again = _Plex(dead=dead)
|
plex_on["plex"] = again = _Plex(dead=dead, gone=gone)
|
||||||
assert plex_people.warm_portraits(db, 100) == {"cached": 0}
|
assert plex_people.warm_portraits(db, 100) == {"cached": 0}
|
||||||
assert again.asked == [] # dead ones marked, live ones cached: nothing to ask for
|
assert again.asked == [] # dead ones marked, live ones cached: nothing to ask for
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user