优化sync_system代码质量
This commit is contained in:
@@ -33,6 +33,7 @@ def _build_default_push_steps() -> List[Dict[str, str]]:
|
||||
class ApiClient:
|
||||
"""API HTTP 客户端"""
|
||||
_TRACE_TEXT_MAX_LEN = 1000
|
||||
_REQUEST_STATS_LOG_PREFIX = "📊 ApiClient request stats"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -72,6 +73,9 @@ class ApiClient:
|
||||
self._rate_limit_window_seconds = float(rate_limit_window_seconds)
|
||||
self._rate_limit_lock = asyncio.Lock()
|
||||
self._rate_limit_timestamps: deque[float] = deque()
|
||||
self._request_total = 0
|
||||
self._request_success = 0
|
||||
self._request_failure = 0
|
||||
|
||||
def _is_rate_limit_enabled(self) -> bool:
|
||||
return self._rate_limit_max_requests > 0 and self._rate_limit_window_seconds > 0
|
||||
@@ -105,9 +109,38 @@ class ApiClient:
|
||||
|
||||
async def close(self):
|
||||
"""关闭 HTTP 客户端"""
|
||||
self.log_request_stats()
|
||||
if self._client:
|
||||
await self._client.aclose()
|
||||
self._client = None
|
||||
|
||||
def get_request_stats(self) -> Dict[str, int]:
|
||||
"""返回当前客户端生命周期内的请求统计。"""
|
||||
return {
|
||||
"total": self._request_total,
|
||||
"success": self._request_success,
|
||||
"failure": self._request_failure,
|
||||
}
|
||||
|
||||
def format_request_stats(self) -> str:
|
||||
"""格式化当前客户端生命周期内的请求统计。"""
|
||||
stats = self.get_request_stats()
|
||||
return (
|
||||
f"{self._REQUEST_STATS_LOG_PREFIX}: "
|
||||
f"total={stats['total']}, success={stats['success']}, failure={stats['failure']}"
|
||||
)
|
||||
|
||||
def log_request_stats(self, level: str = "INFO") -> None:
|
||||
"""输出当前客户端生命周期内的请求统计。"""
|
||||
self._log(self.format_request_stats(), level=level)
|
||||
|
||||
def _log_request_summary(self, *, method: str, endpoint: str, elapsed_seconds: float) -> None:
|
||||
if not self._debug:
|
||||
return
|
||||
self._log(
|
||||
f"ApiClient request: method={method.upper()} endpoint={endpoint} elapsed={elapsed_seconds:.3f}s",
|
||||
level="DEBUG",
|
||||
)
|
||||
|
||||
def _log(self, message: str, level: str = "DEBUG"):
|
||||
"""
|
||||
@@ -382,6 +415,7 @@ class ApiClient:
|
||||
client = self._get_client()
|
||||
url = f"{self._base_url}{endpoint}"
|
||||
await self._acquire_rate_limit_slot()
|
||||
self._request_total += 1
|
||||
|
||||
# 记录请求信息
|
||||
self._log(f"\n{'='*60}", level="DEBUG")
|
||||
@@ -433,6 +467,7 @@ class ApiClient:
|
||||
|
||||
# 记录响应时间
|
||||
elapsed = time.time() - start_time
|
||||
self._log_request_summary(method=method, endpoint=endpoint, elapsed_seconds=elapsed)
|
||||
self._log(f"Response Time: {elapsed:.3f}s", level="DEBUG")
|
||||
|
||||
# 检查 HTTP 状态
|
||||
@@ -453,14 +488,17 @@ class ApiClient:
|
||||
response=result,
|
||||
elapsed_ms=int(elapsed * 1000),
|
||||
)
|
||||
self._request_success += 1
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
self._request_failure += 1
|
||||
|
||||
# 记录错误
|
||||
elapsed = time.time() - start_time
|
||||
self._log_request_summary(method=method, endpoint=endpoint, elapsed_seconds=elapsed)
|
||||
error_msg = "\n========== [ApiClient HTTP Error] ==========\n"
|
||||
error_msg += f"Request: {method} {url}\n"
|
||||
error_msg += f"Params: {params}\n"
|
||||
|
||||
@@ -20,6 +20,7 @@ from typing import ClassVar, Dict, List, Any, Optional, TYPE_CHECKING, TypeVar
|
||||
from pydantic import BaseModel, ValidationError
|
||||
|
||||
from ...common.type_safety import get_pydantic_model_fields
|
||||
from ...logging import get_logger
|
||||
from ..handler import BaseNodeHandler
|
||||
from ..task_result import TaskResult
|
||||
from ..handler import ValidationResult # Import ValidationResult
|
||||
@@ -30,6 +31,7 @@ if TYPE_CHECKING:
|
||||
from .client import ApiClient
|
||||
|
||||
T = TypeVar("T", bound=BaseModel)
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class BaseApiHandler(BaseNodeHandler[T]):
|
||||
@@ -67,6 +69,16 @@ class BaseApiHandler(BaseNodeHandler[T]):
|
||||
"""设置 Collection(由 DataSource 调用)"""
|
||||
self._collection = collection
|
||||
|
||||
def ensure_api_client(self) -> 'ApiClient':
|
||||
if self.api_client is None:
|
||||
raise RuntimeError("API client not set. Call set_api_client() before invoking API handler methods.")
|
||||
return self.api_client
|
||||
|
||||
def ensure_collection(self) -> 'DataCollection':
|
||||
if self._collection is None:
|
||||
raise RuntimeError("Collection not set. Call set_collection() before invoking handler methods.")
|
||||
return self._collection
|
||||
|
||||
@property
|
||||
def node_type(self) -> str:
|
||||
"""返回节点类型"""
|
||||
@@ -109,8 +121,7 @@ class BaseApiHandler(BaseNodeHandler[T]):
|
||||
def _create_basic_node(self, data: Dict[str, Any], depend_ids: Optional[List[str]] = None) -> "SyncNode":
|
||||
"""创建或复用基础节点(默认使用 data['id'] 或 data['_id'])"""
|
||||
data_id = str(data.get("id") or data.get("_id") or "")
|
||||
if self._collection is None:
|
||||
raise RuntimeError("Collection not set. Call set_collection() before creating nodes.")
|
||||
self.ensure_collection()
|
||||
|
||||
if data_id:
|
||||
existing_node = self._collection.get_by_data_id(self.node_type, data_id)
|
||||
@@ -329,10 +340,10 @@ class BaseApiHandler(BaseNodeHandler[T]):
|
||||
|
||||
if diff_fields:
|
||||
node_info = f"[{node_id}]" if node_id else ""
|
||||
print(f" [DIFF] {self.node_type}{node_info} schema={schema.__name__}")
|
||||
logger.info(" [DIFF] %s%s schema=%s", self.node_type, node_info, schema.__name__)
|
||||
for k, v in diff_fields.items():
|
||||
orig_v = origin_dict.get(k)
|
||||
print(f" • {k}: {orig_v!r} → {v!r}")
|
||||
logger.info(" • %s: %r → %r", k, orig_v, v)
|
||||
|
||||
return diff_fields if diff_fields else None
|
||||
|
||||
|
||||
@@ -37,9 +37,10 @@ from ..engine import (
|
||||
StateMachineRuntime,
|
||||
e40_sync_execute,
|
||||
)
|
||||
from ..logging import get_logger
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class BaseDataSource(ABC):
|
||||
@@ -460,7 +461,7 @@ class BaseDataSource(ABC):
|
||||
# Handler 加载数据并创建节点
|
||||
nodes = await handler.load()
|
||||
|
||||
print(f"Loaded nodes for {node_type}: {len(nodes)}")
|
||||
logger.info("Loaded nodes for %s: %d", node_type, len(nodes))
|
||||
|
||||
# 将节点写入 Collection:优先按 data_id 命中已有节点并更新
|
||||
await self._upsert_loaded_nodes(handler, node_type, nodes)
|
||||
@@ -468,7 +469,7 @@ class BaseDataSource(ABC):
|
||||
# 统计加载的节点数
|
||||
self._stats[node_type]["loaded"] += len(nodes)
|
||||
except Exception as exc:
|
||||
print(f"❌ [{node_type}] 加载失败: {exc}")
|
||||
logger.error("❌ [%s] 加载失败: %s", node_type, exc)
|
||||
continue
|
||||
|
||||
# ========== 同步执行 ==========
|
||||
@@ -639,7 +640,7 @@ class BaseDataSource(ABC):
|
||||
f"in_progress={create_in_progress}, failed={create_failed}, skipped={create_skipped}"
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"❌ [{handler.node_type}] create_all 异常: {e}")
|
||||
logger.error("❌ [%s] create_all 异常: %s", handler.node_type, e)
|
||||
for node in create_nodes:
|
||||
ok = self._apply_sync_execute_state(
|
||||
node,
|
||||
@@ -656,7 +657,7 @@ class BaseDataSource(ABC):
|
||||
for result in update_results:
|
||||
await self._handle_task_result(handler, result, async_tasks)
|
||||
except Exception as e:
|
||||
print(f"❌ [{handler.node_type}] update_all 异常: {e}")
|
||||
logger.error("❌ [%s] update_all 异常: %s", handler.node_type, e)
|
||||
for node in update_nodes:
|
||||
ok = self._apply_sync_execute_state(
|
||||
node,
|
||||
|
||||
Reference in New Issue
Block a user