Client-go中的watch接口的resultChan会自动关闭

Client-go中的watch接口的resultChan会自动关闭

问题描述

在client-go工程中,有时候需要用到watch接口,实际场景如下:

namespacesWatch, err := clientSet.CoreV1().Namespaces().Watch(metav1.ListOptions{
   })
if err != nil {
   
    klog.Errorf("create watch error, error is %s, program exit!", err.Error())
    panic(err)
}
for {
   
    select e, ok := <-namespacesWatch.ResultChan()
    if e.Object == nil {
   
        // 这个时候一般是chan已经被关闭了,可以顺便开看下ok是不是flase。
    } else {
   
        // 正常处理逻辑
    }
}

watch的resultChan会周期性的关闭,我不知道这个周期是不是可以设置,但是我在github的issue中看到,有人5分钟就自动关闭了,我的集群是大概40分钟左右,进一步的追究需要深入,我这边就说我遇到的问题以及解决方法吧。问题就是resultChan会定期自动关闭。github上client-go项目对于该问题的Issues: https://github.com/kubernetes/client-go/issues/623, 上面有大佬回复:No, the server will close watch connections regularly. Re-establishing a watch at the last-received resourceVersion is a normal part of maintaining a watch as a client. There are helpers to do this for you in https://github.com/kubernetes/client-go/tree/master/tools/watch。是有官方解决方法的去client-go的tools目录下的watch文件夹下看下。

resultChan会自动关闭的原因

看一下watch.go中的部分代码:

// Interface can be implemented by anything that knows how to watch and report changes.
type Interface interface {
   
	// Stops watching. Will close the channel returned by ResultChan(). Releases
	// any resources used by the watch.
	Stop()

	// Returns a chan which will receive all the events. If an error occurs
	// or Stop() is called, this channel will be closed, in which case the
	// watch should be completely cleaned up.  !!!明确说了在出现错误或者被调用Stop时,通道会自动关闭的
	ResultChan() <-chan Event
}

我们接着看下有哪些error和哪些情况会调用stop,我就开始追watch方法的那个对象,最后追到这里streamwatcher.go,Ok,这里就可以看到watch实际对象了,struct的中参数可以看下,有result的通道,互斥锁和Stoppe标志接收是否已经结束了的标志位。看下NewStreamWatcher方法,关注其中的go sw.receive(),在返回对象前就起了协程在接收数据了,那接着去看receive函数,看一下receive那边的注释,我写的中文注释,就是在解码遇到错误是就会选择return,return前看下defer sw.Stop()等清理操作。这样就跟上面对上了!

// StreamWatcher turns any stream for which you can write a Decoder interface
// into a watch.Interface.
type StreamWatcher struct {
   
	sync.Mutex
	source   Decoder
	reporter Reporter
	result   chan Event
	stopped  bool
}

// NewStreamWatcher creates a StreamWatcher from the given decoder.
func NewStreamWatcher(d Decoder, r Reporter) *StreamWatcher {
   
	sw := &StreamWatcher{
   
		source:   d,
		reporter: r,
		// It's easy for a consumer to add buffering via an extra
		// goroutine/channel, but impossible for them to remove it,
		// so nonbuffered is better.
		result: make(chan Event),
	}
	go sw.receive()// !!!看这里,新建完对象就开始接收数据了
	return sw
}

// ResultChan implements Interface.
func (sw *StreamWatcher) ResultChan() <-chan Event {
   
	return sw.result
}

// Stop implements Interface.
func (sw *StreamWatcher) Stop() {
   
	// Call Close() exactly once by locking and setting a flag.
	sw.Lock()
	defer sw.Unlock()
	if !sw.stopped {
   
		sw.stopped = true
		sw.source.Close()
	}
}

// stopping returns true if Stop() was called previously.
func (sw *StreamWatcher) stopping() bool {
   
	sw.Lock()
	defer sw.Unlock()
	return sw.stopped
}

// receive reads result from the decoder in a loop and sends down the result channel.
func (sw *StreamWatcher) receive() {
   
	defer close(sw.result)
	defer sw.Stop()// 注意看这里,这个方法退出前就会调用stop函数
	defer utilruntime.HandleCrash()
	for {
   // for循环,一直接收
		action, obj, err := sw.source.Decode()
		if err != nil {
   //以下是接收到的错,反正有错误就会return
			// Ignore expected error.
			if sw.stopping() {
   
				return
			}
			switch err {
   
			case io.EOF:
				// watch closed normally
			case io.ErrUnexpectedEOF:
				klog.V
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值