mongo.connect必须配context.withtimeout,不能用context.background();不设超时会导致dns失败或网络抖动时无限等待,服务启动卡住、kubernetes pod pending,goroutine永久挂起,正确做法是用context.withtimeout(context.background(), 10*time.second)并defer cancel()。

mongo.Connect 必须配 context.WithTimeout,不能用 context.Background()
不设超时的 mongo.Connect 在 DNS 解析失败、网络抖动或 MongoDB 未就绪时会无限等待,服务启动卡住、日志无报错,Kubernetes Pod 就一直 Pending。这不是“连接慢”,是 goroutine 永久挂起,最终拖垮整个实例。
正确做法是:
- 用
context.WithTimeout(context.Background(), 10*time.Second)包裹,10 秒足够覆盖绝大多数部署场景(比 MongoDB 默认connectTimeoutMS=30000短,但留出 ping 验证时间) -
defer cancel()必须写,漏掉会导致 context 泄漏,GC 压力持续上升 - 每次重试连接都该用新 context,不要复用同一个
ctx实例
URI 必须显式声明 authSource、TLS 和特殊字符编码
本地 mongodb://localhost:27017 能连通,上线后大概率静默失败——错误信息常是模糊的 invalid URI 或直接 connection refused,根本看不出问题在哪。
真实环境 URI 至少要补全这些 query 参数:
- 用户在
admin库创建,操作myapp库:URI 写成mongodb://user:pass@host:27017/myapp?authSource=admin - TLS 启用时,测试加
?tls=true&tlsInsecure=true;生产必须指定 CA:?tls=true&tlsCAFile=/etc/ssl/mongo-ca.pem - 密码含
/、@、:等字符:先用url.PathEscape()编码,否则驱动解析失败
client 必须全局复用 + 显式调用 Ping 验证
每次请求都新建 *mongo.Client?那不是集成,是制造连接风暴。连接池没被复用,SetMaxPoolSize(20) 这类参数就等于白设。
关键动作只有两个:
- client 全局变量初始化一次,比如放在
internal/repository/mongo.go里导出 - 初始化后立刻执行
client.Ping(ctx, readpref.Primary()),传readpref.Primary()而非nil,否则副本集可能误连 secondary 并返回 stale 数据 - 应用退出前调用
client.Disconnect(ctx),不然进程退出时连接不会优雅关闭
bson tag 错一个字母,Decode 就全为零值
MongoDB 驱动不做 schema 校验,字段映射失败不报错,只默默把 struct 字段设为零值。你看到 Name == ""、ID == primitive.NilObjectID,实际是因为 `bson:"nmae"` 拼错了,或者漏写了 _id 字段的 primitive.ObjectID 类型声明。
容易踩的坑:
-
_id字段类型必须是primitive.ObjectID,不是string,否则 decode 失败且静默为零值 - 嵌套结构体要逐层加 tag,内层字段不会继承外层前缀
-
bson:",omitempty"对bool和int慎用——false、0也会被跳过,不是仅跳过nil - 时间字段建议统一存 UTC,filter 里用
time.Now().UTC()对齐,避免时区错乱
最麻烦的是这种问题:代码能跑、没 panic、日志没报错,但数据就是空。查起来得一层层核对 tag 拼写、类型、嵌套层级——比语法错误更难定位。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











