消息路由函数必须接收 context.Context,正确签名应为 func (c *ChatRoom) Route(ctx context.Context, from, to, msg string) error,所有下游调用需传入该 ctx 并检查 ctx.Err(),to 应为 string 类型,路由逻辑须通过注入的 send 函数转发而非直接调用同事方法,注册时须严格校验用户非空与唯一性。

消息路由函数必须接收 context.Context
不带 context.Context 的路由函数在真实项目中几乎必然出问题。只要消息分发涉及日志写入、数据库操作、HTTP 调用或下游限流,就会立刻卡住 goroutine 或无法响应取消信号。
常见错误是定义成:func (c *ChatRoom) Route(from, to, msg string) —— 看似简洁,但一旦 to 对应的用户正在写磁盘日志,整个路由就阻塞,后续消息全积压。
- 正确签名应为:
func (c *ChatRoom) Route(ctx context.Context, from, to, msg string) error - 所有下游调用(查用户、发通知、写审计日志)都需传入该
ctx,并检查ctx.Err() - 若
to == ""或to == "all",广播分支也必须支持超时控制,不能无条件遍历
to 字段应按字符串路由,而非 interface{} 或泛型
用 string 作为目标标识是最轻量、最易调试的选择。实际项目里不需要抽象出 Target 接口或泛型参数,那只会增加类型断言和序列化开销。
典型误用:func (c *ChatRoom) Send(from string, target interface{}, msg string) —— 这样就得在内部做 v, ok := target.(string) 或更糟的 reflect.ValueOf(target).String(),既慢又易 panic。
立即学习“go语言免费学习笔记(深入)”;
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 私聊场景:直接查
c.users[to],to是用户名,天然可索引 - 广播场景:约定
to == "broadcast"或空字符串,统一走c.broadcast()分支 - 群组场景:扩展为
to == "group:dev-team",用strings.HasPrefix(to, "group:")判断即可,无需新类型
路由函数内部不应直接调用同事方法,而应通过注入的 send 函数转发
如果 Route 里直接写 c.users[to].Receive(msg),就等于把同事耦合进中介者实现,违背模式本意。同事应只暴露接收能力,不暴露结构体字段或方法名。
更危险的是:同事的 Receive 方法若本身含锁或阻塞逻辑,会拖垮整个路由 goroutine。
- 推荐做法:每个同事注册时传入一个
send func(string),由中介者在Route中调用它 - 这个
send可以是闭包,封装了重试、序列化、异步投递等逻辑,同事完全无感知 - 测试时可把
send替换为func(s string) { log.Println("mock send:", s) },无需 mock 结构体
注册用户时必须做非空和重复检查,否则 Route 会 panic
Route 函数最常触发 panic 的地方不是并发竞争,而是 c.users[to] 返回 nil 后直接解引用——比如用户未注册、注册失败被忽略、或注册名与发送时的 to 不一致。
典型疏漏:只检查 user != nil,却没验证 user.Name 是否为空,导致 c.users[""] = user 覆盖了广播入口。
- 注册函数开头加:
if user == nil || user.Name == "" { return errors.New("invalid user") } - 查表前加:
if u, ok := c.users[to]; !ok { return fmt.Errorf("user %q not found", to) } - 避免静默兜底(如自动创建临时用户),这会让问题延迟暴露且难以追踪
Route 函数,而是让每次调用都落在可观察、可中断、可替换的边界上。函数签名里的 context.Context、参数里的 string、转发时的 send func(),三者缺一不可——它们共同构成了一条可控的消息链路,而不是一个黑盒调度器。


















