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

浙公网安备 33010602011771号