掘金 后端 ( ) • 2024-04-24 10:15
config := etcdv3.Config{
    Endpoints: []string{"invalid:2379"},
    DialTimeout: 2*time.Second,
}
client, err := etcdv3.New(config)
if err != nil {
    panic(err)
}
...
// keep alive
lease, err := client.Grant(ctx, ttl)
if err != nil {
    panic(err)
}

执行以上代码按道理,是会返回错误的,但是在项目部署阶段却发现代码运行到lease, err := client.Grant(ctx, ttl)这个地方的时候会阻塞在这边,没有任何错误的返回。

初步解决办法

config := etcdv3.Config{
    Endpoints: []string{"invalid:2379"},
    DialTimeout: 2*time.Second,
}
client, err := etcdv3.New(config)
if err != nil {
    panic(err)
}
...
timeoutCtx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
_, err = cli.Status(timeoutCtx, srv.EtcdAddrs[0])
if err != nil {
    return err
}
// keep alive
lease, err := client.Grant(ctx, ttl)
if err != nil {
    panic(err)
}

这样按照预期的返回错误了,但是不够优雅,而且这么做就等于是固定了etcd的数量,也不灵活
后来在github官方仓库翻,看到一篇issue,讲的就是这个问题#9877,虽然说是长连接,但是错误的连接总得报错是吧
最终的解决方案

config := etcdv3.Config{
    Endpoints: []string{"invalid:2379"},
    DialTimeout: 2*time.Second,
    DialOptions: []grpc.DialOption{grpc.WithBlock()},
}
client, err := etcdv3.New(config)
if err != nil {
    panic(err)
}

这样就能按照预期,输入错误的地址,会返回错误...Error while dialing: dial tcp xxx:xxx: connect: connection refused...的错误信息