feat(HEL-382): 搭建 datahub 底座和盘后正式数据链路
新增独立 xiaobai-datahub 服务(SQLite WAL、Tushare 盘后发布、/v1 契约和管理后台),不改现站页面与数据链路。 Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
co-authored by
Cursor
multica-agent
parent
c2ebc0ab91
commit
3498dd7a4b
@@ -0,0 +1,35 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from collections.abc import Callable
|
||||
from typing import TypeVar
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class RetryError(RuntimeError):
|
||||
def __init__(self, message: str, attempts: int, last_error: BaseException | None = None) -> None:
|
||||
super().__init__(message)
|
||||
self.attempts = attempts
|
||||
self.last_error = last_error
|
||||
|
||||
|
||||
def retry_call(
|
||||
fn: Callable[[], T],
|
||||
attempts: int = 5,
|
||||
base_delay: float = 0.2,
|
||||
max_delay: float = 8.0,
|
||||
sleeper: Callable[[float], None] = time.sleep,
|
||||
retry_on: tuple[type[BaseException], ...] = (Exception,),
|
||||
) -> T:
|
||||
last: BaseException | None = None
|
||||
for attempt in range(1, max(1, attempts) + 1):
|
||||
try:
|
||||
return fn()
|
||||
except retry_on as exc:
|
||||
last = exc
|
||||
if attempt >= attempts:
|
||||
break
|
||||
delay = min(max_delay, base_delay * (2 ** (attempt - 1)))
|
||||
sleeper(delay)
|
||||
raise RetryError(f"retry exhausted after {attempts} attempts: {last}", attempts, last)
|
||||
Reference in New Issue
Block a user