Go本身不支持热重载,所有方案均为进程级重启;air启动失败90%是Go代码编译错误,需先执行go build定位问题;监听非.go文件须在[watch]和[build]两节均配置include_ext;权限不足或路径不一致会导致fork/exec失败。

Go 框架本身不支持热重载,所有“热重载”都是靠外部工具监听文件 + 杀旧进程 + 启新进程实现的;选错工具或配错路径,90% 的失败不是代码问题,而是 air 或 realize 找不到 go.mod、读不到正确二进制、或监听漏了后缀。
air 启动就报 failed to build,先别碰 .air.toml
这几乎总是 Go 代码编译失败,不是配置问题。终端最后一行红字才是真相:
-
undefined: xxx→ 缺变量或函数,go build直接跑一遍就能定位 -
import cycle not allowed→ 循环引用,go list -f '{{.Imports}}' ./...可辅助排查 -
cannot find module providing package→go.mod不在当前目录,air默认从含go.mod的根启动,别在cmd/api里直接运行
改 config.yaml 或 template.html 不重启?两处 include_ext 必须都写
air 默认只监听 .go 文件,其他后缀必须显式声明,且要出现在两个位置:
-
[watch]节里的include_ext = ["go", "yaml", "yml", "html", "tmpl"] -
[build]节里**同样一份**include_ext,否则变更不会触发构建 - 加太多后缀会耗尽 inotify 句柄(Linux 默认 8192),大项目建议只加真正需要 reload 的扩展名
fork/exec ./tmp/main: permission denied 怎么修
这是 macOS/Linux 上最常见执行失败,根源是生成的二进制没执行权限,或路径不一致:
立即学习“go语言免费学习笔记(深入)”;
-
build.cmd写成go build -o ./tmp/main . && chmod +x ./tmp/main(加chmod) -
build.bin必须和build.cmd输出路径完全一致:如果 cmd 是./tmp/main,bin 就不能是tmp/main或./main -
tmp_dir对应目录要有写权限,ls -ld tmp看是否可写
配置热加载 ≠ 进程热重载,别混用场景
改 config.yaml 后希望服务立刻用新值,这不是 air 的事,得自己用 fsnotify 监听并安全替换:
-
viper.WatchConfig()只注册监听,不自动重读 —— 必须在回调里调viper.ReadInConfig()和viper.Unmarshal() - 用
atomic.Value存配置指针,业务代码统一通过conf.Load().(*Config)读取,禁止缓存旧指针 - 数据库连接池大小变更后,要调
db.SetMaxOpenConns()才生效;HTTP 超时参数无法热更,只能 graceful restart
真正容易被忽略的是:热重载只解决“代码改了要不要重启”,而配置热加载解决的是“配置改了要不要重新初始化组件”。两者触发时机、作用范围、并发安全要求完全不同,强行塞进一个工具里,反而更容易出状态不一致的问题。


















