
为什么 lambda.Start 必须是 main 函数的最后一条语句
因为 lambda.Start 是阻塞调用,内部启动了 HTTP 监听循环(Lambda Runtime API 的长轮询),一旦它开始运行,后续代码永远不会执行。如果你在它之后写了日志、清理逻辑或 defer,那些都会被跳过。
- 常见错误现象:
defer close(db)没触发、log.Println("done")不输出、本地测试时程序“卡住”但无报错 - 正确姿势:所有初始化(如 DB 连接、配置加载、中间件注册)必须在
lambda.Start之前完成 - 注意
lambda.Start接收的是 handler 函数值,不是调用结果 —— 别写成lambda.Start(handler())
Go Lambda handler 函数签名怎么写才不被 runtime 拒绝
AWS Lambda Go 运行时只认两种签名:带 context.Context 的和不带的;参数类型和返回值顺序错一个字符就会报 Unable to marshal response 或直接冷启动失败。
- 最稳妥签名:
func(context.Context, events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) - 别用
http.Request或自定义 struct 当输入 —— Lambda 不传 HTTP 对象,只传 JSON 解析后的events.*结构体 - 返回值必须是
(T, error)形式,其中T要能被json.Marshal;返回map[string]interface{}虽然能跑,但字段名大小写、空值处理容易出错,建议用官方events.APIGatewayProxyResponse - 如果用 ALB 或 SQS 触发,要换对应 events 包,比如
events.SQSEvent,不能复用 API Gateway 的结构体
本地调试时 lambda.Start 报错 “fork/exec /proc/self/exe: no such file or directory” 怎么办
这是 Go 构建产物没打包进容器镜像,或者本地用 go run 直接执行导致的 —— lambda.Start 在本地会尝试 exec 自身二进制来模拟 Runtime API 交互,而 go run 没有可执行文件。
- 必须用
go build -o main main.go编译出二进制,再运行./main - Docker 镜像里确保
CMD ["./main"]指向正确的可执行路径,且权限为755 - 推荐加个构建检查:
file ./main确认是 ELF 可执行文件,不是文本或链接 - 如果用
aws-lambda-go/lambda/handler的 mock 方式测试 handler 逻辑,就绕过lambda.Start,直接调用 handler 函数传入 mock context 和 event
并发请求下全局变量和 init() 里的资源复用有哪些坑
Lambda 容器可能复用进程处理多个请求,但 Go runtime 不保证 goroutine 安全 —— 全局变量、未加锁的 map、共享的 http.Client 如果没配好 Transport,会引发 panic 或连接耗尽。
立即学习“go语言免费学习笔记(深入)”;
- DB 连接池(如
*sql.DB)可以全局复用,但必须在init()或main()开头初始化,且SetMaxOpenConns建议设为 0(不限制)或按并发预估设低值(Lambda 默认并发软限制是 1000) -
http.Client必须复用,且Transport.MaxIdleConnsPerHost至少设为 100,否则高并发下大量 TIME_WAIT 和 dial timeout - 绝对不要在 handler 里修改全局 map/slice —— 即使加了
sync.Mutex,也容易因生命周期混乱导致死锁;改用sync.Map或每次新建局部结构体 - 环境变量和
os.Getenv是安全的,但别在 handler 里反复解析 JSON 配置 —— 提前在 init 里解析并存为全局 const var










