使用Go语言Viper包无法动态更新配置文件问题排查
问题分析与解决方案
核心问题
- 传参类型错误:
uploadFilesFromLocation接收的是azblob.Blob值类型,启动goroutine时传入的是初始blob的拷贝,后续OnConfigChange更新的全局blob指针和goroutine内的实例完全无关,上传逻辑始终用旧的容器配置。 - Viper重复触发:编辑器保存配置文件时,通常会生成临时文件再替换原文件,导致fsnotify触发两次
Write事件,这是正常现象,可通过过滤事件类型解决。 - 初始化错误:原代码中
fileLocation未从config读取配置值,属于语法错误。
具体修复步骤
1. 修复uploadFilesFromLocation的参数与逻辑
将函数参数改为指针类型,确保上传逻辑始终引用最新的Blob实例:
// 修改函数定义为指针接收 func uploadFilesFromLocation(location string, blob *azureBlob.Blob) { for { files, err := os.ReadDir(location) utils.HandleError(err) for _, file := range files { // 直接使用传入的指针实例,每次上传都会用最新的配置 go blob.UploadFileToBlob(file.Name()) // 注意原方法名拼写错误:BLob → Blob } // 添加轮询间隔,避免频繁扫描目录 time.Sleep(5 * time.Second) } }
2. 修正goroutine启动传参
启动时传入全局blob指针:
// 先正确初始化fileLocation fileLocation := utils.FileLocation{ ROOT_DIR: config.ROOT_DIR, SUB_DIR_1: config.SUB_DIR_1, SUB_DIR_2: config.SUB_DIR_2, } filelocation := fileLocation.GetDirectoryLocation() // 传入指针,而非值拷贝 go uploadFilesFromLocation(filelocation, blob)
3. 过滤Viper重复触发事件
在OnConfigChange中只处理Write类型事件,避免重复执行:
viper.OnConfigChange(func(e fsnotify.Event) { // 只处理文件写入事件,忽略其他类型(如创建临时文件) if e.Op&fsnotify.Write != fsnotify.Write { return } err := viper.Unmarshal(&config) utils.HandleError(err) log.Println("Config Changed") // 更新全局blob指针,goroutine会自动引用最新实例 blob = &azureBlob.Blob{ AccountName: config.ACCOUNT_NAME, AccountKey: config.ACCOUNT_KEY, ContainerName: config.CONTAINER_NAME, } })
4. 修正azureBlob.go中的方法名拼写
将UploadFileToBLob改为UploadFileToBlob,避免调用错误:
func (b *Blob) UploadFileToBlob(file string) { // 原有逻辑不变 }
验证逻辑
修改配置文件的CONTAINER_NAME后:
- 控制台只会打印一次"Config Changed"
- 后续扫描到的新文件会上传至新容器
- 正在上传的文件不受影响(因为上传goroutine启动时已经使用了当时的配置,这是合理的,若要中断正在上传的任务需额外处理)
内容的提问来源于stack exchange,提问作者rangarajan
相关产品推荐
相关产品推荐

