3.1 KiB
3.1 KiB
任务017:重构审查问题修复
目标
修复TCP服务重构审查发现的P0/P1问题。
修复清单
P0:Redis类型冲突
位置: device-server/src/main.rs
问题: register_node用SET(string类型),heartbeat用HSET(hash类型),同一key操作触发WRONGTYPE错误。
修复: 统一用HSET:
// 节点注册
async fn register_node(redis: &Redis, node_id: &str, ip: &str, tcp_port: u16) {
redis.hset(&format!("node:{}", node_id), &[
("ip", ip),
("tcp_port", &tcp_port.to_string()),
("status", "online"),
("last_heartbeat", &Instant::now().elapsed().as_secs().to_string()),
]).await;
redis.expire(&format!("node:{}", node_id), 300).await;
}
// 节点心跳
async fn heartbeat(redis: &Redis, node_id: &str) {
redis.hset(&format!("node:{}", node_id), &[
("last_heartbeat", &Instant::now().elapsed().as_secs().to_string()),
]).await;
redis.expire(&format!("node:{}", node_id), 300).await;
}
P1:节点管理双轨制
问题: API服务维护内存NodeRegistry,设备服务直接写Redis,两者不关联。
修复方案A(推荐): API服务从Redis读取节点信息
// API服务节点列表
async fn list_nodes(redis: &Redis) -> Result<Json<Vec<NodeInfo>>> {
let keys = redis.keys("node:*").await?;
let mut nodes = Vec::new();
for key in keys {
let node_id = key.strip_prefix("node:").unwrap();
let info: HashMap<String, String> = redis.hgetall(&key).await?;
nodes.push(NodeInfo {
id: node_id.to_string(),
ip: info.get("ip").cloned().unwrap_or_default(),
tcp_port: info.get("tcp_port").and_then(|p| p.parse().ok()).unwrap_or(0),
status: info.get("status").cloned().unwrap_or_default(),
last_heartbeat: info.get("last_heartbeat").cloned().unwrap_or_default(),
});
}
Ok(Json(nodes))
}
修复方案B: 设备服务通过HTTP注册到API服务
- 设备服务启动时POST到
/api/nodes/register - API服务存内存
- 心跳POST到
/api/nodes/:id/heartbeat - 注销POST到
/api/nodes/:id/deregister
P2:配置系统
问题: 代码用dotenvy读环境变量,config.toml形同虚设。
修复: 二选一
- 方案A:用
tomlcrate读config.toml - 方案B:删除config.toml,只用.env
P3:协议结构体重复
问题: DeviceMessage等结构体在两个服务中重复定义。
修复: 暂不处理,后续提取shared crate时统一。
P4:限流器同步Mutex
问题: 限流器用std::sync::Mutex,不符合异步规范。
修复: 改用tokio::sync::Mutex或RwLock。
质量约束
- 完成代码后执行
cargo check+cargo clippy,零报错零警告 - 分层拆分,单函数≤80行,命名语义化,完整注释
- 所有外部IO/网络请求异常捕获,禁止裸panic
- 分支逻辑全覆盖,不遗漏兜底分支
- 常量抽离,不使用废弃API
- Rust内存安全,合理管理所有权,禁用unsafe无合理理由