fix: retry 3 times create new release script

This commit is contained in:
Emilien
2026-10-19 09:28:14 +02:00
parent 57cc097022
commit efcfb1ef03
2 changed files with 57 additions and 23 deletions

View File

@@ -37,6 +37,7 @@ permissions:
jobs: jobs:
prepare-release: prepare-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 45
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v7
with: with:

View File

@@ -44,6 +44,7 @@ import os
import re import re
import subprocess import subprocess
import sys import sys
import time
import urllib.error import urllib.error
import urllib.request import urllib.request
@@ -52,6 +53,10 @@ DEFAULT_MODEL = "deepseek/deepseek-v4-flash-0731"
REPO_URL = "https://github.com/iv-org/invidious" REPO_URL = "https://github.com/iv-org/invidious"
CHANGELOG_FILE = "CHANGELOG.md" CHANGELOG_FILE = "CHANGELOG.md"
SHARD_FILE = "shard.yml" SHARD_FILE = "shard.yml"
LLM_ATTEMPTS = 3
# Per-attempt wall-clock limit. The socket timeout alone is not enough, as
# OpenRouter keeps idle connections alive by trickling whitespace.
LLM_DEADLINE = 600
def die(msg): def die(msg):
@@ -212,29 +217,57 @@ def call_llm(base_url, api_key, model, prompt):
], ],
"temperature": 0.3, "temperature": 0.3,
} }
req = urllib.request.Request( data = json.dumps(payload).encode("utf-8")
url, data=json.dumps(payload).encode("utf-8"), headers = {
headers={ "Authorization": f"Bearer {api_key}",
"Authorization": f"Bearer {api_key}", "Content-Type": "application/json",
"Content-Type": "application/json", # OpenRouter-specific attribution headers; ignored by other APIs.
# OpenRouter-specific attribution headers; ignored by other APIs. "HTTP-Referer": REPO_URL,
"HTTP-Referer": REPO_URL, "X-Title": "Invidious release changelog",
"X-Title": "Invidious release changelog", }
}, method="POST") error = None
try: for attempt in range(1, LLM_ATTEMPTS + 1):
with urllib.request.urlopen(req, timeout=180) as resp: if error:
body = json.loads(resp.read().decode("utf-8")) print(f"LLM attempt {attempt - 1}/{LLM_ATTEMPTS} failed: {error}; "
except urllib.error.HTTPError as exc: "retrying...", file=sys.stderr)
die(f"LLM API HTTP {exc.code}: {exc.read().decode('utf-8', 'replace')}") time.sleep(10 * (attempt - 1))
except urllib.error.URLError as exc: req = urllib.request.Request(url, data=data, headers=headers,
die(f"LLM API request failed: {exc}") method="POST")
try: try:
content = body["choices"][0]["message"]["content"].strip() deadline = time.monotonic() + LLM_DEADLINE
except (KeyError, IndexError): raw = b""
die(f"unexpected LLM API response: {json.dumps(body)[:1000]}") with urllib.request.urlopen(req, timeout=180) as resp:
if not content: while chunk := resp.read1(8192):
die("LLM API returned empty content") raw += chunk
return content if time.monotonic() > deadline:
raise TimeoutError(f"no answer after {LLM_DEADLINE}s")
body = json.loads(raw.decode("utf-8"))
except urllib.error.HTTPError as exc:
error = f"HTTP {exc.code}: {exc.read().decode('utf-8', 'replace')}"
# Client errors (bad key, unknown model...) won't fix themselves.
if exc.code < 500 and exc.code != 429:
break
continue
except (urllib.error.URLError, TimeoutError) as exc:
error = f"request failed: {exc}"
continue
except json.JSONDecodeError as exc:
error = f"invalid JSON response: {exc}"
continue
try:
choice = body["choices"][0]
except (KeyError, IndexError, TypeError):
error = f"unexpected response: {json.dumps(body)[:1000]}"
continue
# Providers may return a choice with null content (upstream error,
# all tokens spent on reasoning...); report why instead of crashing.
content = ((choice.get("message") or {}).get("content") or "").strip()
if content:
return content
error = ("empty content (finish_reason="
f"{choice.get('finish_reason')!r}, "
f"error={json.dumps(choice.get('error') or body.get('error'))})")
die(f"LLM API failed after {attempt} attempt(s): {error}")
def generate_prose(prs, version, base_url, api_key, model): def generate_prose(prs, version, base_url, api_key, model):