“还是老样子,又是一个背景交代。
最近公司一直在搞降本增效,各种优化。期间发现一些服务的配置文件热加载经常更新失败,一番分析之后,发现是框架里使用了 viper 的文件监控和热加载的功能,在一些特殊的使用姿势的情况下,会引发更新bug。”
具体场景
关于热加载的使用方式,在脱敏之后的代码大概张下面这个样子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| package main
import ( "encoding/json" "fmt" "net/http" "time"
"github.com/fsnotify/fsnotify" "github.com/gin-gonic/gin" "github.com/spf13/viper" "github.com/willas/overseer" )
var ( FusingConfig cfg ) type cfg struct { Test item } type item struct { List []int }
func main() { serverAddr := fmt.Sprintf(":8989") overseer.Run(overseer.Config{ Program: prog, Address: serverAddr, Debug: true, }) }
func prog(state overseer.State) { confFile := "/data/demo/demo.toml" fmt.Println("cfgFile: ", confFile) LoadConfig(confFile) viper.WatchConfig() viper.OnConfigChange(func(e fsnotify.Event) { fmt.Println("Config file changed:", e.Op) LoadConfig(confFile) }) err := http.Serve(state.Listener, gin.New()) if err != nil { fmt.Println("server start failed", err) } time.Sleep(time.Second) }
func LoadConfig(cfgFile string) { viper.SetConfigFile(cfgFile) err := viper.ReadInConfig() if err != nil { fmt.Println("viper read config error", err) return } err = viper.Unmarshal(&FusingConfig) if err != nil { fmt.Println("viper unmarshal error", err) return } fByte, _ := json.MarshalIndent(FusingConfig, "", " ") fmt.Println("changed file content:\n", string(fByte)) }
|
配置文件
其中加载的配置文件内容如下:
bug的表现场景是:当对list数组元素进行删减时,无法正确的更新删减后的内容
截图说明
- 二图胜千言:
初次加载配置内容:

可以看到热加载之后的配置文件内容没有符合预期。
