Viper远程配置踩坑记录

尝试etcd做配置中心,就用了Viper。没想到踩了一堆坑,记录一下。

一开始的代码是这么写的,想着先监听再读取:

func initViperRemote() {
	err := viper.AddRemoteProvider("etcd3",
		"http://127.0.0.1:12379", "webook")
	if err != nil {
		panic(err)
	}
	viper.SetConfigType("yaml")
	// 先watch
	err = viper.WatchRemoteConfig()
	if err != nil {
		panic(err)
	}
	// 再read
	err = viper.ReadRemoteConfig()
	if err != nil {
		panic(err)
	}
}

直接panic。

第一个坑:invalid memory address or nil pointer dereference

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x9a8d6b]

goroutine 1 [running]:
github.com/spf13/viper.(*Viper).watchRemoteConfig(0xc000162a80, {0xf653d0?, 0xc0000b5240?})
...

查了下,原来是顺序搞反了,必须先成功Read一次,才能Watch

func initViperRemote() {
	err := viper.AddRemoteProvider("etcd3",
		"http://127.0.0.1:12379", "webook")
	if err != nil {
		panic(err)
	}
	viper.SetConfigType("yaml")

	// 先read
	err = viper.ReadRemoteConfig()
	if err != nil {
		panic(err)
	}
    // 再watch
	err = viper.WatchRemoteConfig()
	if err != nil {
		panic(err)
	}
}

又panic了。

第二个坑:Enable the remote features by doing a blank import

panic: Remote Configurations Error: Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'
...

这个错误信息倒是很直接,让干啥就干啥。要用远程功能得先匿名导入它的包。

import (
	"bytes"
	"fmt"
	"net/http"

	"github.com/fsnotify/fsnotify"
	"github.com/gin-gonic/gin"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
	_ "github.com/spf13/viper/remote" // 加上这行
)

再跑,还是panic。

第三个坑:No Files Found

panic: Remote Configurations Error: No Files Found
...

这就奇怪了,我明明用etcdctl把配置放进去了。

$ etcdctl --endpoints=127.0.0.1:12379 put /webook "$(<dev.yaml)"
OK
$ etcdctl --endpoints=127.0.0.1:12379 get /webook
/webook
db:
  dsn: "root:root@tcp(localhost:13316)/webook"
...

看了一下代码和命令,发现了问题。etcd里的key是/webook,代码里写的是webook。差一个斜杠。

改代码:

func initViperRemote() {
	err := viper.AddRemoteProvider("etcd3",
		"http://127.0.0.1:12379", "/webook") // 这里加上斜杠
    // ...
}

再跑,总算成功了。

kbz@DESKTOP-PCAC9DA:~/BackendDEV/geektime-basic-go/webook$ go run .
[db.dsn redis.addr]
map[db:map[dsn:root:root@tcp(localhost:13316)/webook] redis:map[addr:localhost:6379]]
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
...
[GIN-debug] Listening and serving HTTP on :7070

感觉Viper的接口设计得有点恶心,用起来比较折腾。不过在要求灵活配置优先级的场景下确实,使用状态机模型会契合一点

posted @ 2025-09-25 17:06  KBZ232  阅读(18)  评论(0)    收藏  举报