ForcePilot/backend/package/yuxi/channels/auth/backoff.py
Kris 655eab7230 feat(auth): add complete auth toolkit module
新增了完整的认证工具库模块,包含以下功能:
1. 指数退避重试组件
2. 敏感数据过滤与日志脱敏
3. 安全策略管理引擎
4. 认证健康监控模块
5. SSRF防护工具集
6. 多类型token管理系统
7. 密钥管理器加解密工具
2026-05-13 16:18:51 +08:00

66 lines
1.7 KiB
Python

from __future__ import annotations
import asyncio
import random
import time
from dataclasses import dataclass
@dataclass
class BackoffConfig:
base_seconds: float = 5.0
max_seconds: float = 300.0
jitter_pct: float = 0.2
multiplier: float = 2.0
class ExponentialBackoff:
def __init__(self, config: BackoffConfig | None = None):
self._config = config or BackoffConfig()
self._attempt = 0
self._last_attempt_time: float = 0
@property
def attempt(self) -> int:
return self._attempt
@property
def next_delay(self) -> float:
if self._attempt == 0:
return 0
base = min(
self._config.base_seconds * (self._config.multiplier ** (self._attempt - 1)),
self._config.max_seconds,
)
jitter = base * self._config.jitter_pct * (random.random() * 2 - 1)
return base + jitter
def reset(self) -> None:
self._attempt = 0
self._last_attempt_time = 0
def mark_attempt(self) -> None:
self._attempt += 1
self._last_attempt_time = time.monotonic()
async def wait(self) -> None:
delay = self.next_delay
if delay > 0:
await asyncio.sleep(delay)
async def execute(self, func, *args, **kwargs):
while True:
try:
self.mark_attempt()
return await func(*args, **kwargs)
except Exception as e:
if not _is_retryable(e):
raise
if self.next_delay >= self._config.max_seconds:
raise
await self.wait()
def _is_retryable(exception: Exception) -> bool:
return getattr(exception, "retryable", False)