【GoLang】etcd初始化客户端时不会返回错误怎么办

问题描述

今天遇到一个奇怪问题,我在初始化一个etcd客户端时,传入了一个错误的端点,然后就水灵灵的初始化成功了,没有触发err。

这直接导致后续的etcd操作永久阻塞,而且不利于错误排查。。。。

Go 复制代码
package main

import (
	"context"
	"fmt"
	clientv3 "go.etcd.io/etcd/client/v3"
	"go.uber.org/zap"
	"time"
)

func main() {
	cli, err := clientv3.New(clientv3.Config{
		Endpoints:   []string{"127.0.0.1:2378"},	// 传入一个错误端口2378
		DialTimeout: 5 * time.Second,
	})
	if err != nil {    // err为 nil
		fmt.Printf("clientv3.New() err: %v", err)
		return
	}

}

后来我查了一下,原因如下:

clientv3.New 在创建客户端时,不会立即验证端点的有效性或是否可连接,而是将验证推迟到实际使用客户端(比如执行 Put、Get 等操作)时。

err 为 nil 并不一定意味着端点是正确的,而是说明 clientv3.New 在初始化时没有检测到明显的配置错误。真正的连接问题可能在后续操作中暴露出来。

解决方式

我们在初始化完成之后,直接验证该端点的有效性。(类似于ping),如果验证出错就 return,验证正确就继续执行。

Go 复制代码
package main

import (
	"context"
	"fmt"
	clientv3 "go.etcd.io/etcd/client/v3"
	"go.uber.org/zap"
	"time"
)

func main() {
	cli, err := clientv3.New(clientv3.Config{
		Endpoints:   []string{"127.0.0.1:2378"}, // 传入一个错误端口2378
		DialTimeout: 5 * time.Second,
	})
	if err != nil {
		fmt.Printf("clientv3.New() err: %v", err)
		return
	}

	// 验证端点有效性
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()
	_, err = cli.Status(ctx, "127.0.0.1:2378")
	if err != nil {
		fmt.Printf("验证端点有效性失败 cli.Status() %v\n", err)
		cli.Close() // 记得关
		return
	}

}

实际跑一下,输出如下:

bash 复制代码
{"level":"warn","ts":"2025-04-03T15:16:38.336886+0800","logger":"etcd-client","caller":"v3@v3.5.12/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"etcd-endpoints://0xc0000f61c0/127.0.0.1:2378","attempt":0,"error":"rpc error: code = DeadlineExceeded desc = latest balancer error: connection error: desc = \"transport: Error while dialing: dial tcp 127.0.0.1:2378: connectex: No connection could be made because the target machine actively refused it.\""}
验证端点有效性失败 cli.Status() context deadline exceeded

第一行是clientv3内部自动输出的一条日志,其中描述了错误原因:Error while dialing: dial tcp 127.0.0.1:2378: connectex: No connection could be made because the target machine actively refused it

第二行则是我们手动输出的err,只描述了上下文超时错误。

这样一来,错误的端点就会在此被检查出来,我们就成功实现了验证。

但是,描述了错误原因的这条日志,他只是自动打印在控制台了,并不是打印在日志文件中,这样我们日后还是不方便排查问题,那我们如何将其打印在日志文件中呢?有需求的小伙伴可以继续往下看。

将报错打印到日志文件

我们只需要在初始化客户端时,加入一个字段即可。

相关推荐
ModStart29 分钟前
通知:两个致命紧急PHP漏洞需要修改
后端
高频因子挖掘机1 小时前
A股量化第一步:如何利用 QuantDash 实现日K数据清洗、前复权校验与缺失值处理
后端·github·api
张彦峰ZYF1 小时前
借与还之间:连接池设计的技术难点与实现推演
后端·架构·连接池·服务端与协议·无锁借还与尾延迟·失效模式与探活时机·状态污染与泄漏检测
LEE2 小时前
为什么你的 Claude Code 还在转圈等,别人的已经干完三件事了?
前端·后端·ai编程
喵个咪2 小时前
GoWind CMS 拆解:给 NL2SQL 上四把锁——智能问数的安全边界
后端
喵个咪2 小时前
GoWind CMS 拆解:在 Go 里给 TipTap 搭一套 Yjs 协同后端
后端·go·cms
不像程序员的程序媛2 小时前
springboot支持的web容器
前端·spring boot·后端
喵个咪2 小时前
GoWind Admin 拆解:一个 Sender 接口接 39 个通知渠道
后端·架构·go
用户69371750013842 小时前
当你向领导申请 AI 编程工具预算时,如果领导追问“能提效多少,有量化数据吗”,你该怎么回答?
android·后端·ios
喵个咪2 小时前
GoWind CMS 拆解:社交分发引擎——10 平台适配器、状态闸门与自愈定时任务
后端·go·cms