diff --git a/monitor/nacos.py b/monitor/nacos.py index 4a77bc7..517a8e5 100644 --- a/monitor/nacos.py +++ b/monitor/nacos.py @@ -26,6 +26,7 @@ from .config import ( NACOS_PASSWORD, NACOS_TIMEOUT_SECONDS, NACOS_USERNAME, + load_hosts, utc_now, ) @@ -39,6 +40,20 @@ TOKEN_VALUE = "" # Nacos access token 失效时间。 TOKEN_EXPIRES_AT = 0.0 +# 复用现有部署链路里的 Nacos 注册名映射。 +NACOS_SERVICE_NAME_MAP = { + "auth": "rc-auth", + "gateway": "rc-gateway", + "external": "rc-service-external", + "console": "rc-service-console", + "other": "rc-service-other", + "live": "rc-service-live", + "wallet": "rc-service-wallet", + "order": "rc-service-order", +} +# 反向映射,便于把注册名转回页面上的业务名。 +FRIENDLY_SERVICE_NAME_MAP = {value: key for key, value in NACOS_SERVICE_NAME_MAP.items()} + def nacos_truthy(value: Any) -> bool: # 布尔值直接返回。 @@ -219,6 +234,42 @@ def split_grouped_service_name(raw_name: str) -> tuple[str, str]: return NACOS_DISCOVERY_GROUP, raw_name +def monitored_service_queries() -> list[dict[str, str]]: + # 读取当前 targets.json 里实际存在的服务名。 + service_names = sorted( + { + str(service.get("name") or "").strip() + for host in load_hosts() + for service in host.get("services") or [] + if str(service.get("name") or "").strip() + } + ) + + # 这里构造要查的注册目标。 + queries: list[dict[str, str]] = [] + + # 逐个业务服务转成 Nacos 注册名。 + for display_name in service_names: + registry_name = NACOS_SERVICE_NAME_MAP.get(display_name) + + # 没映射的服务先跳过,比如当前 golang 不走 Nacos 注册。 + if not registry_name: + continue + + # 追加查询目标。 + queries.append( + { + "displayName": display_name, + "registryName": registry_name, + "groupName": NACOS_DISCOVERY_GROUP, + "rawServiceName": f"{NACOS_DISCOVERY_GROUP}@@{registry_name}", + } + ) + + # 返回需要主动查询的服务清单。 + return queries + + def list_services(namespace_id: str) -> list[str]: # 这里逐页拉取 service list。 doms: list[str] = [] @@ -343,15 +394,34 @@ def build_nacos_payload() -> dict[str, Any]: # 逐个 namespace 读取服务和实例。 for namespace in normalized_namespaces: - # 当前 namespace 的服务列表。 + # 当前 namespace 的自动发现结果。 raw_services = list_services(namespace["namespaceId"]) + # 这里保存当前 namespace 下所有待查询服务。 + queries_by_key: dict[tuple[str, str], dict[str, str]] = {} - # 逐个服务拉实例详情。 + # 先收 service/list 返回的服务。 for raw_name in raw_services: # 解析 group 和真正的 serviceName。 - group_name, service_name = split_grouped_service_name(raw_name) + group_name, registry_name = split_grouped_service_name(raw_name) + # 保存查询项。 + queries_by_key[(group_name, registry_name)] = { + "displayName": FRIENDLY_SERVICE_NAME_MAP.get(registry_name, registry_name), + "registryName": registry_name, + "groupName": group_name, + "rawServiceName": raw_name, + } + + # 再补上 targets.json 里已知的注册服务,避免 service/list 返回空时整页丢数据。 + for item in monitored_service_queries(): + queries_by_key.setdefault( + (item["groupName"], item["registryName"]), + item, + ) + + # 逐个服务拉实例详情。 + for query in queries_by_key.values(): # 拉取当前服务实例。 - instance_items = list_instances(namespace["namespaceId"], service_name, group_name) + instance_items = list_instances(namespace["namespaceId"], query["registryName"], query["groupName"]) # 归一化实例结构。 normalized_instances: list[dict[str, Any]] = [] @@ -410,9 +480,10 @@ def build_nacos_payload() -> dict[str, Any]: { "namespaceId": namespace["namespaceId"], "namespaceName": namespace["name"], - "rawServiceName": raw_name, - "serviceName": service_name, - "groupName": group_name, + "rawServiceName": query["rawServiceName"], + "serviceName": query["displayName"], + "registryServiceName": query["registryName"], + "groupName": query["groupName"], "level": level, "instanceTotal": current_total, "healthyTotal": healthy_total,