Give oversized-video retries a much longer budget than stall retries

Confirmed on a real post: VK can still be transcoding lower renditions 8+
minutes after publish, so a few seconds of backoff wasn't enough margin.
Size-exceeded failures now get their own retry budget (5 attempts, 90s
apart - up to 7.5 extra minutes) instead of sharing the short 3s backoff
meant for stalls/timeouts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-05 00:13:19 +05:00
parent d01a17146e
commit 0e1f25384e
2 changed files with 28 additions and 11 deletions
+6
View File
@@ -83,6 +83,12 @@ class Settings(BaseSettings):
# Extra attempts after a transient failure (stall/timeout/network hiccup) before
# falling back to a link-only post. Permanent failures (private/removed/etc.) never retry.
yt_dlp_retry_attempts: int = 2
# A fresh upload's lower-quality renditions can still be mid-transcode on VK's side,
# so a height-capped URL briefly serves the full-res master and trips our size check -
# confirmed on a real post still happening 8 minutes after publish. Needs a separate,
# much longer retry budget than the generic stall/timeout case above.
yt_dlp_size_retry_attempts: int = 5
yt_dlp_size_retry_delay_sec: float = 90.0
# Text Styling & Decoration
header_text: str = ""
+22 -11
View File
@@ -102,24 +102,35 @@ class MediaProcessor:
async def download_video_ytdlp(
self, url: str, prefix: str = "video_"
) -> tuple[Optional[Path], Optional[str], bool]:
"""Retries transient failures (stalls, timeouts, one-off yt-dlp/network hiccups)
a couple of times before giving up - a single flaky attempt used to fall straight
through to the link-only fallback even though the video was perfectly downloadable."""
"""Retries transient failures before giving up - a single flaky attempt used to fall
straight through to the link-only fallback even though the video was perfectly
downloadable. Stalls/timeouts/network hiccups get a couple of quick retries; a
size-exceeded result (likely VK still transcoding lower renditions) switches to a
much longer, more patient retry budget - see yt_dlp_size_retry_* in config.py."""
last_result: tuple[Optional[Path], Optional[str], bool] = (None, "video download failed", False)
for attempt in range(1, settings.yt_dlp_retry_attempts + 2):
attempt = 0
max_attempts = settings.yt_dlp_retry_attempts + 1
delay = 3.0
while attempt < max_attempts:
attempt += 1
path, err, is_permanent = await self._download_video_ytdlp_attempt(url, prefix)
if path or is_permanent:
return path, err, is_permanent
last_result = (path, err, is_permanent)
if attempt <= settings.yt_dlp_retry_attempts:
# A fresh upload's lower-quality renditions can still be mid-transcode on
# VK's side - the "720p" URL then briefly serves the full-res master until
# the ladder catches up, which trips our size cap. That's not a permanent
# rejection, just needs more time than a stalled connection does.
delay = 60.0 if "exceeds size limit" in (err or "") else 3.0
# A fresh upload's lower-quality renditions can still be mid-transcode on
# VK's side - the "720p" URL then briefly serves the full-res master until
# the ladder catches up, which trips our size cap. Confirmed on a real post
# still happening 8 minutes after publish, so this needs a much longer and
# more patient retry budget than a stalled connection does - switch to it
# (and restart the attempt count) the first time we see this specific error.
if "exceeds size limit" in (err or "") and max_attempts != settings.yt_dlp_size_retry_attempts + 1:
max_attempts = settings.yt_dlp_size_retry_attempts + 1
delay = settings.yt_dlp_size_retry_delay_sec
attempt = 0
if attempt < max_attempts:
logger.warning(
"yt-dlp attempt {}/{} failed transiently for {}: {} - retrying in {}s",
attempt, settings.yt_dlp_retry_attempts + 1, url, err, delay,
attempt, max_attempts, url, err, delay,
)
await asyncio.sleep(delay)
return last_result