应封装channel而非裸用:裸用chan interface{}会导致阻塞、事件丢失、竞态分发和类型不安全;推荐用map[string][]chan封装实现类型安全的发布/订阅。

用 channel 做事件总线,但别直接裸用
Go 没有内建事件总线,channel 是最常用替代方案,但它不是开箱即用的“事件系统”。直接用 chan interface{} 广播事件,会立刻遇到阻塞、漏收、类型不安全问题。
- 订阅者必须在事件发生前就已启动并接收,否则事件丢失;
- 多个 goroutine 从同一
chan读取,无法保证谁收到哪条——这不是发布/订阅,是竞态分发; - 没类型约束,
select里混着处理string、error、自定义结构体,运行时 panic 风险高; - 推荐做法:封装一层,用
map[string][]chan 管理主题(topic),每个 topic 对应一个无缓冲或带缓冲的 <code>chan,写入前做类型断言或用泛型约束; - 缓冲大小要按场景设:
1适合通知类事件(如配置重载),64或更高适合日志聚合类高频低延迟场景。
用 sync.Map 存事件处理器,但注意 key 的可比性
动态注册/注销事件回调时,常把 handler 存进 sync.Map。看似合理,但 key 设计错一步,就会导致重复注册或删不掉 handler。
- 别用闭包函数字面量当 key——每次调用生成新地址,
sync.Map.Load()找不到旧 handler; - 推荐用字符串标识符(如
"user.created")或自定义 struct(字段全为可比较类型,不含slice、map、func); - 如果 handler 带状态(比如依赖某个
*http.Client),别把整个 handler 当 key,而应提取稳定标识(如 client 的 host + timeout); -
sync.Map不保证遍历顺序,别假设 handler 调用顺序——需要顺序执行时,显式维护切片 +sync.RWMutex更可控。
用 context.Context 控制事件生命周期,别让 goroutine 泄漏
事件驱动容易催生大量长期存活的 goroutine,尤其是监听文件变更、消息队列或定时触发的事件源。一旦主逻辑退出,这些 goroutine 还在跑,就是泄漏。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 所有事件监听循环必须接受
context.Context,并在ctx.Done()触发时 clean up; - 别在 handler 里起 goroutine 后就撒手不管,要用
context.WithCancel或context.WithTimeout传递下游控制权; - 常见坑:用
time.Ticker触发事件,但没调用ticker.Stop()—— 它不会随 context 自动停; - 验证是否泄漏:测试中 defer 调用
runtime.GC()+runtime.NumGoroutine()断言,上线后用 pprof/goroutines endpoint 观察。
选第三方库前先看清楚它怎么处理 panic 和背压
像 github.com/ThreeDotsLabs/watermill 或 github.com/segmentio/kafka-go 这类“事件驱动”库,实际是消息中间件客户端,不是轻量级事件总线。它们对错误的默认策略可能和你预期相反。
- handler 里 panic,默认行为可能是重试无限次(kafka)或丢弃消息(nats)——得主动 recover 并发到死信 channel;
- 背压处理常被忽略:当消费者处理不过来,消息堆积在内存 buffer 还是写磁盘?buffer 满了是阻塞生产者还是丢弃?查清
MaxInFlight、QueueCapacity这类配置项的实际作用; - 很多库用反射解析事件结构体,字段名大小写、tag 不匹配就静默失败——加单元测试用真实 event payload 跑一遍解码流程;
- 真要简单事件广播,自己写 50 行带泛型和 context 支持的
EventBus更透明,也更容易 debug。
事件驱动的复杂点不在“怎么发”,而在“谁收到了、什么时候收到、没收到怎么办、收到后 panic 了谁兜底”。这些细节藏在 channel 缓冲策略、context 取消传播、panic 恢复边界里,而不是架构图上那个漂亮的 Event Bus 圆圈里。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










