| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
[feature]增加Mooncake Conductor故障恢复的RAS能力 Co-authored-by: zhoujing101<zhoujing101@huawei.com> # message auto-generated for no-merge-commit merge: !337 merge master into master [feature]增加Mooncake Conductor故障恢复的RAS能力 Created-by: zhoujing101 Commit-by: zhoujing101 Merged-by: towncharlie Description: ## **1. 合入背景** Mooncake Conductor缺少RAS能力,发生故障重启后,无法正常重新工作。 需要增加重注册能力,依赖mooncake社区PR( https://github.com/kvcache-ai/Mooncake/pull/2595 ) 合入后提供查询已注册实例信息接口。 [#212](https://gitcode.com/Ascend/MindIE-PyMotor/issues/212) ## **2. 修改内容** 开启kv cache亲和性调度时,每隔30秒(可配置,配置为0则不重注册)会去conductor获取一次实例列表(依赖PR: https://github.com/kvcache-ai/Mooncake/pull/2595 ),对比差异,将缺少的实例补注册到Condutor。 ## **3. 资料变更** “不涉及”。 ## **4. 接口变更** “不涉及”。 ## **5. 测试结果** 正常情况:  当mooncake conductor发生重启时:  ## **6. CheckList** > PR提交人对以下CheckList自检项进行全量自检,自检通过或不涉及,均修改 [ ] 为 [x] [x] 代码注释完备 [x] 正确记录维测日志 [x] 是否有UT用例 [x] 若涉及多线程场景,考虑了并发场景,不存在死锁问题 --- # 测试用例总结 ## 1. tests/config/test_config_utils.py — 配置解析(9 个用例) ### TestResolveReRegisterIntervalSec | 测试方法 | 覆盖场景 | 预期结果 | |---|---|---| | test_returns_default_when_motor_coordinator_missing | 顶层 motor_coordinator_config 键缺失 | 返回 DEFAULT_RE_REGISTER_INTERVAL_SEC (30) | | test_returns_default_when_motor_coordinator_not_dict | motor_coordinator_config 值不是 dict | 返回默认值 30 | | test_returns_default_when_prefill_kv_event_config_missing | motor_coordinator 存在但缺少 prefill_kv_event_config | 返回默认值 30 | | test_returns_default_when_prefill_kv_event_config_not_dict | prefill_kv_event_config 存在但不是 dict | 返回默认值 30 | | test_returns_default_when_re_register_interval_missing | prefill_kv_event_config 中缺少 re_register_interval_sec | 返回默认值 30 | | test_returns_default_when_re_register_interval_is_none | re_register_interval_sec 显式设为 None | 返回默认值 30 | | test_returns_configured_value | 正常传入 120 | 返回 int 120 | | test_accepts_string_value | 传入字符串 "45" | 返回 int 45 | | test_accepts_zero | 传入 0(禁用定时器) | 返回 int 0 | --- ## 2. tests/coordinator/api_client/test_conductor_api_client.py — Conductor API 客户端(28 个用例) ### TestConductorInstanceId(4 个) | 测试方法 | 覆盖场景 | 预期结果 | |---|---|---| | test_role_u_returns_union_prefix | ROLE_U 实例 | conductor_instance_id() 返回 "vllm-union-7" | | test_role_p_returns_prefill_prefix | ROLE_P 实例 | conductor_instance_id() 返回 "vllm-prefill-3" | | test_role_e_falls_to_prefill_prefix | ROLE_E 实例(非 U 回退) | conductor_instance_id() 返回 "vllm-prefill-5" | | test_role_d_falls_to_prefill_prefix | ROLE_D 实例(非 U 回退) | conductor_instance_id() 返回 "vllm-prefill-9" | ### TestBuildRegisterPayload(5 个) | 测试方法 | 覆盖场景 | 预期结果 | |---|---|---| | test_returns_empty_dict_when_endpoint_format_invalid | endpoint 没有 *: 分隔符 | 返回空 dict {} | | test_basic_payload_without_replay | 标准 payload,无 replay_endpoint | 返回含 endpoint/type/modelname/block_size/instance_id/dp_rank 的 dict | | test_payload_with_replay_endpoint | 带 replay_endpoint 配置 | payload 包含 replay_endpoint 字段,端口为 base + endpoint.id | | test_payload_dp_rank_uses_endpoint_id | dp_rank 取自 endpoint.id(非 0) | dp_rank == 5,endpoint 端口为 5557 + 5 = 5562 | | test_replay_endpoint_format_invalid_no_star_colon | replay_endpoint 没有 *: 分隔符 | payload 中**不包含** replay_endpoint 键 | ### TestNormalizeServiceKey(9 个) | 测试方法 | 覆盖场景 | 预期结果 | |---|---|---| | test_all_uppercase_keys | Conductor 返回大写 key | 正确提取四个字段值 | | test_lowercase_keys_not_found_by_uppercase_lookup | 只有小写 key(大写 key 不存在) | 全部返回默认值 ("", -1, "", "") | | test_dp_rank_zero | dp_rank=0被正确解析 | dp_rank == 0 | | test_dp_rank_missing_defaults_to_minus_one | DPRank 完全缺失 | 默认 -1 | | test_dp_rank_non_numeric_string_returns_minus_one | DPRank 为非数值字符串 "abc" | 返回 -1 | | test_dp_rank_empty_string_returns_minus_one | DPRank 为空字符串 "" | 返回 -1(isdigit=False) | | test_instance_id_empty_when_missing | InstanceID 缺失 | instance_id == "" | | test_endpoint_empty_when_missing | Endpoint 缺失 | endpoint == "" | | test_replay_endpoint_empty_when_missing | ReplayEndpoint 缺失 | replay_endpoint == "" | | test_instance_id_empty_when_missing | InstanceID 缺失 | instance_id == "" | | test_endpoint_empty_when_missing | Endpoint 缺失 | endpoint == "" | | test_replay_endpoint_empty_when_missing | ReplayEndpoint 缺失 | replay_endpoint == "" | ### TestGetRegisteredServices(4 个) | 测试方法 | 覆盖场景 | 预期结果 | |---|---|---| | test_returns_services_list | Conductor /services 正常返回 | 返回 services 列表 | | test_returns_empty_when_response_not_dict | 响应不是 dict | 返回空列表 [] | | test_returns_empty_when_services_not_list | services 字段不是 list | 返回空列表 [] | | test_raises_on_http_error | HTTP 请求异常 | 向上抛出原始异常 | ### TestReRegisterKvInstances(6 个) | 测试方法 | 覆盖场景 | 预期结果 | |---|---|---| | test_skip_when_no_registered_services | get_registered_services() 抛出异常(Conductor 不可用) | 跳过,register_post 不被调用 | | test_skip_non_kva_roles | ROLE_D / ROLE_E 不在 _KVA_ROLES 中 | register_post 不被调用 | | test_skip_when_payload_empty | _build_register_payload() 返回空 dict | register_post 不被调用 | | test_re_registers_when_service_missing | 本地实例在 Conductor 中不存在 | register_post 被调用一次 | | test_skips_when_already_registered | 实例已在 Conductor 中注册(所有字段匹配) | register_post **不**被调用 | | test_re_registers_only_missing_among_multiple | 多个 endpoint,仅 dp_rank=1 缺失 | register_post 仅被调用一次(ep_id=1) | --- ## 覆盖率统计 | 模块 | 覆盖函数/方法 | |---|---| | motor.config.config_utils._resolve_re_register_interval_sec | 全部 9 条分支 | | motor.coordinator.api_client.conductor_api_client.conductor_instance_id | 2 条分支(U / 非 U) | | ConductorApiClient._build_register_payload | endpoint 格式、replay 有无、replay 格式 | | ConductorApiClient._normalize_service_key | 大写/小写 key、dp_rank=0 边界、字段缺失默认值、非数值字符串、空字符串 | | ConductorApiClient.get_registered_services | 正常/格式错误/异常 | | ConductorApiClient.re_register_kv_instances | Conductor 不可用、非 KVA 跳过、payload 为空、新注册、已注册跳过、部分缺失 | See merge request: Ascend/MindIE-PyMotor!337 | 8 天前 | |
[feature]增加Mooncake Conductor故障恢复的RAS能力 Co-authored-by: zhoujing101<zhoujing101@huawei.com> # message auto-generated for no-merge-commit merge: !337 merge master into master [feature]增加Mooncake Conductor故障恢复的RAS能力 Created-by: zhoujing101 Commit-by: zhoujing101 Merged-by: towncharlie Description: ## **1. 合入背景** Mooncake Conductor缺少RAS能力,发生故障重启后,无法正常重新工作。 需要增加重注册能力,依赖mooncake社区PR( https://github.com/kvcache-ai/Mooncake/pull/2595 ) 合入后提供查询已注册实例信息接口。 [#212](https://gitcode.com/Ascend/MindIE-PyMotor/issues/212) ## **2. 修改内容** 开启kv cache亲和性调度时,每隔30秒(可配置,配置为0则不重注册)会去conductor获取一次实例列表(依赖PR: https://github.com/kvcache-ai/Mooncake/pull/2595 ),对比差异,将缺少的实例补注册到Condutor。 ## **3. 资料变更** “不涉及”。 ## **4. 接口变更** “不涉及”。 ## **5. 测试结果** 正常情况:  当mooncake conductor发生重启时:  ## **6. CheckList** > PR提交人对以下CheckList自检项进行全量自检,自检通过或不涉及,均修改 [ ] 为 [x] [x] 代码注释完备 [x] 正确记录维测日志 [x] 是否有UT用例 [x] 若涉及多线程场景,考虑了并发场景,不存在死锁问题 --- # 测试用例总结 ## 1. tests/config/test_config_utils.py — 配置解析(9 个用例) ### TestResolveReRegisterIntervalSec | 测试方法 | 覆盖场景 | 预期结果 | |---|---|---| | test_returns_default_when_motor_coordinator_missing | 顶层 motor_coordinator_config 键缺失 | 返回 DEFAULT_RE_REGISTER_INTERVAL_SEC (30) | | test_returns_default_when_motor_coordinator_not_dict | motor_coordinator_config 值不是 dict | 返回默认值 30 | | test_returns_default_when_prefill_kv_event_config_missing | motor_coordinator 存在但缺少 prefill_kv_event_config | 返回默认值 30 | | test_returns_default_when_prefill_kv_event_config_not_dict | prefill_kv_event_config 存在但不是 dict | 返回默认值 30 | | test_returns_default_when_re_register_interval_missing | prefill_kv_event_config 中缺少 re_register_interval_sec | 返回默认值 30 | | test_returns_default_when_re_register_interval_is_none | re_register_interval_sec 显式设为 None | 返回默认值 30 | | test_returns_configured_value | 正常传入 120 | 返回 int 120 | | test_accepts_string_value | 传入字符串 "45" | 返回 int 45 | | test_accepts_zero | 传入 0(禁用定时器) | 返回 int 0 | --- ## 2. tests/coordinator/api_client/test_conductor_api_client.py — Conductor API 客户端(28 个用例) ### TestConductorInstanceId(4 个) | 测试方法 | 覆盖场景 | 预期结果 | |---|---|---| | test_role_u_returns_union_prefix | ROLE_U 实例 | conductor_instance_id() 返回 "vllm-union-7" | | test_role_p_returns_prefill_prefix | ROLE_P 实例 | conductor_instance_id() 返回 "vllm-prefill-3" | | test_role_e_falls_to_prefill_prefix | ROLE_E 实例(非 U 回退) | conductor_instance_id() 返回 "vllm-prefill-5" | | test_role_d_falls_to_prefill_prefix | ROLE_D 实例(非 U 回退) | conductor_instance_id() 返回 "vllm-prefill-9" | ### TestBuildRegisterPayload(5 个) | 测试方法 | 覆盖场景 | 预期结果 | |---|---|---| | test_returns_empty_dict_when_endpoint_format_invalid | endpoint 没有 *: 分隔符 | 返回空 dict {} | | test_basic_payload_without_replay | 标准 payload,无 replay_endpoint | 返回含 endpoint/type/modelname/block_size/instance_id/dp_rank 的 dict | | test_payload_with_replay_endpoint | 带 replay_endpoint 配置 | payload 包含 replay_endpoint 字段,端口为 base + endpoint.id | | test_payload_dp_rank_uses_endpoint_id | dp_rank 取自 endpoint.id(非 0) | dp_rank == 5,endpoint 端口为 5557 + 5 = 5562 | | test_replay_endpoint_format_invalid_no_star_colon | replay_endpoint 没有 *: 分隔符 | payload 中**不包含** replay_endpoint 键 | ### TestNormalizeServiceKey(9 个) | 测试方法 | 覆盖场景 | 预期结果 | |---|---|---| | test_all_uppercase_keys | Conductor 返回大写 key | 正确提取四个字段值 | | test_lowercase_keys_not_found_by_uppercase_lookup | 只有小写 key(大写 key 不存在) | 全部返回默认值 ("", -1, "", "") | | test_dp_rank_zero | dp_rank=0被正确解析 | dp_rank == 0 | | test_dp_rank_missing_defaults_to_minus_one | DPRank 完全缺失 | 默认 -1 | | test_dp_rank_non_numeric_string_returns_minus_one | DPRank 为非数值字符串 "abc" | 返回 -1 | | test_dp_rank_empty_string_returns_minus_one | DPRank 为空字符串 "" | 返回 -1(isdigit=False) | | test_instance_id_empty_when_missing | InstanceID 缺失 | instance_id == "" | | test_endpoint_empty_when_missing | Endpoint 缺失 | endpoint == "" | | test_replay_endpoint_empty_when_missing | ReplayEndpoint 缺失 | replay_endpoint == "" | | test_instance_id_empty_when_missing | InstanceID 缺失 | instance_id == "" | | test_endpoint_empty_when_missing | Endpoint 缺失 | endpoint == "" | | test_replay_endpoint_empty_when_missing | ReplayEndpoint 缺失 | replay_endpoint == "" | ### TestGetRegisteredServices(4 个) | 测试方法 | 覆盖场景 | 预期结果 | |---|---|---| | test_returns_services_list | Conductor /services 正常返回 | 返回 services 列表 | | test_returns_empty_when_response_not_dict | 响应不是 dict | 返回空列表 [] | | test_returns_empty_when_services_not_list | services 字段不是 list | 返回空列表 [] | | test_raises_on_http_error | HTTP 请求异常 | 向上抛出原始异常 | ### TestReRegisterKvInstances(6 个) | 测试方法 | 覆盖场景 | 预期结果 | |---|---|---| | test_skip_when_no_registered_services | get_registered_services() 抛出异常(Conductor 不可用) | 跳过,register_post 不被调用 | | test_skip_non_kva_roles | ROLE_D / ROLE_E 不在 _KVA_ROLES 中 | register_post 不被调用 | | test_skip_when_payload_empty | _build_register_payload() 返回空 dict | register_post 不被调用 | | test_re_registers_when_service_missing | 本地实例在 Conductor 中不存在 | register_post 被调用一次 | | test_skips_when_already_registered | 实例已在 Conductor 中注册(所有字段匹配) | register_post **不**被调用 | | test_re_registers_only_missing_among_multiple | 多个 endpoint,仅 dp_rank=1 缺失 | register_post 仅被调用一次(ep_id=1) | --- ## 覆盖率统计 | 模块 | 覆盖函数/方法 | |---|---| | motor.config.config_utils._resolve_re_register_interval_sec | 全部 9 条分支 | | motor.coordinator.api_client.conductor_api_client.conductor_instance_id | 2 条分支(U / 非 U) | | ConductorApiClient._build_register_payload | endpoint 格式、replay 有无、replay 格式 | | ConductorApiClient._normalize_service_key | 大写/小写 key、dp_rank=0 边界、字段缺失默认值、非数值字符串、空字符串 | | ConductorApiClient.get_registered_services | 正常/格式错误/异常 | | ConductorApiClient.re_register_kv_instances | Conductor 不可用、非 KVA 跳过、payload 为空、新注册、已注册跳过、部分缺失 | See merge request: Ascend/MindIE-PyMotor!337 | 8 天前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 8 天前 | ||
| 8 天前 |