init biliup-next
This commit is contained in:
73
src/biliup_next/app/retry_meta.py
Normal file
73
src/biliup_next/app/retry_meta.py
Normal 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(),
|
||||
}
|
||||
Reference in New Issue
Block a user