init biliup-next

This commit is contained in:
theshy
2026-04-01 00:44:58 +08:00
commit d0cf1fd0df
127 changed files with 15582 additions and 0 deletions

View File

@ -0,0 +1,73 @@
from __future__ import annotations
from datetime import datetime, timedelta, timezone
def parse_iso(value: str | None) -> datetime | None:
if not value:
return None
try:
return datetime.fromisoformat(value)
except ValueError:
return None
def publish_retry_schedule_seconds(settings: dict[str, object]) -> list[int]:
raw_schedule = settings.get("retry_schedule_minutes")
if isinstance(raw_schedule, list):
schedule: list[int] = []
for item in raw_schedule:
if isinstance(item, int) and not isinstance(item, bool) and item >= 0:
schedule.append(item * 60)
if schedule:
return schedule
retry_count = settings.get("retry_count", 5)
retry_count = retry_count if isinstance(retry_count, int) and not isinstance(retry_count, bool) else 5
retry_count = max(retry_count, 0)
retry_backoff = settings.get("retry_backoff_seconds", 300)
retry_backoff = retry_backoff if isinstance(retry_backoff, int) and not isinstance(retry_backoff, bool) else 300
retry_backoff = max(retry_backoff, 0)
return [retry_backoff] * retry_count
def retry_meta_for_step(step, settings_by_group: dict[str, object]) -> dict[str, object] | None: # type: ignore[no-untyped-def]
if getattr(step, "status", None) != "failed_retryable" or getattr(step, "retry_count", 0) <= 0:
return None
if getattr(step, "step_name", None) != "publish":
return None
publish_settings = settings_by_group.get("publish", {})
if not isinstance(publish_settings, dict):
publish_settings = {}
schedule = publish_retry_schedule_seconds(publish_settings)
attempt_index = step.retry_count - 1
if attempt_index >= len(schedule):
return {
"retry_due": False,
"retry_exhausted": True,
"retry_wait_seconds": None,
"retry_remaining_seconds": None,
"next_retry_at": None,
}
wait_seconds = schedule[attempt_index]
reference = parse_iso(getattr(step, "finished_at", None)) or parse_iso(getattr(step, "started_at", None))
if reference is None:
return {
"retry_due": True,
"retry_exhausted": False,
"retry_wait_seconds": wait_seconds,
"retry_remaining_seconds": 0,
"next_retry_at": datetime.now(timezone.utc).isoformat(),
}
next_retry_at = reference + timedelta(seconds=wait_seconds)
now = datetime.now(timezone.utc)
remaining_seconds = max(int((next_retry_at - now).total_seconds()), 0)
return {
"retry_due": now >= next_retry_at,
"retry_exhausted": False,
"retry_wait_seconds": wait_seconds,
"retry_remaining_seconds": remaining_seconds,
"next_retry_at": next_retry_at.isoformat(),
}