直接用 go func() 启动后台任务会导致 goroutine 泄漏、panic 无人捕获、http 上下文取消失效、重启时资源不释放,典型表现为内存持续上涨、连接数居高不下、日志无失败痕迹;必须用带超时的 context 传递至所有下游调用,并采用消息队列实现生产级异步。

直接用 go func() 启动后台任务会出什么问题
不是不能用,而是用了就大概率线上翻车:goroutine 泄漏、panic 无人捕获、HTTP 上下文取消信号失效、重启时资源不释放。最典型的现象是服务内存持续上涨、连接数居高不下、日志里查不到失败原因。
- HTTP handler 的
r.Context()生命周期一结束,ctx.Done()就关闭了,但你起的go func()里如果用的是context.Background()或没传新 context,它根本收不到信号 - 请求体
r.Body在 handler 返回后会被关闭,后台 goroutine 若此时才去读,会得到http: read on closed response body - 没加
defer recover()?一次 panic 就干掉整个 goroutine,还可能连带拖垮调度器 - 并发猛增时,100 个
go doHeavyWork()瞬间拉起,没限流、没排队、没状态跟踪,监控看不出来,运维只能等告警
用 context.WithTimeout 包裹所有阻塞操作才有效
超时不是设个参数就完事——它必须贯穿整个调用链,从 HTTP 入口到 DB 查询、HTTP client.Do、gRPC 调用,每个环节都要显式接收并传递 context。
- 别只在 handler 入口套一层
context.WithTimeout(r.Context(), 5*time.Second),然后把原始r.Context()传给下游;得把新生成的ctx显式传下去:doDBQuery(ctx, ...)、callPaymentService(ctx, ...) - 数据库操作必须用
db.QueryContext(ctx, ...),而不是db.Query(...);HTTP 请求必须用http.NewRequestWithContext(ctx, ...) - gRPC 调用必须每次传带超时的 ctx:
client.GetUser(ctx, req),复用同一个*grpc.ClientConn不代表超时能继承 - 常见坑:
time.AfterFunc+cancel()组合看似能超时,但无法中断已发出的网络请求,只是“事后清理”,实际请求还在飞
真正可靠的异步方案得靠消息队列 + 独立 worker
前端点击“导出订单”这类操作,后端不该在 HTTP 响应里等结果,而该立即返回 task_id,并由另一组进程消费执行——这才是生产级异步。
- RabbitMQ/Kafka 不是银弹,但它们天然支持重试、死信、手动确认(
delivery.Ack(false))、限流和可观测性,比自己手写 goroutine pool 稳定得多 - 入队时必须序列化完整上下文:
trace_id、用户 ID、原始参数 JSON,别存一半在 Redis 再查一半,避免状态不一致 - worker 进程要独立部署,启动时注册唯一
worker_id,每条任务开始前打log.Info("start processing", "task_id", task.ID),方便 trace 关联 - 状态查询走 Redis:
sync.Map不够用,得用redis.HSET task:{id} status running result "" error "" updated_at ...,配合 TTL 防止堆积
前端轮询任务状态时后端容易漏掉的细节
轮询接口看着简单,但几个关键点一漏,前端就永远卡在“处理中”。
- task_id 必须校验格式,比如正则
^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$,否则恶意请求能扫遍 Redis key - 状态更新不能只写一次成功就完事:DB 写入失败、Redis 写入失败、网络抖动,都得有 fallback,比如本地内存缓存 + 定时同步
- 取消指令不是发个信号就结束——worker 消费到 cancel 标记后,得主动调
db.Cancel()、http.Client.CloseIdleConnections()、transaction.Rollback(),否则连接/事务照样挂着 - 超时时间设太短(如 200ms)会导致大量误判,尤其跨机房调用或 TLS 握手耗时波动大,建议按 P99 延迟 + 20% buffer 设置
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











