Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/kubernetes/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 执行与gRPC客户端重新连接的正确方法_Go_Kubernetes_Network Programming_Grpc - Fatal编程技术网

Go 执行与gRPC客户端重新连接的正确方法

Go 执行与gRPC客户端重新连接的正确方法,go,kubernetes,network-programming,grpc,Go,Kubernetes,Network Programming,Grpc,我有一个Go gRPC客户端连接到运行在k8s群集中另一个pod中的gRPC服务器 它工作正常,接收和处理请求 我现在想知道,如果gRPC服务器pod被回收,如何最好地实现恢复能力 据我所知,clientconn.go代码应该自动处理重新连接,但我就是无法让它工作,我担心我的实现在一开始是不正确的 从main调用代码: go func() { if err := gRPCClient.ProcessRequests(); err != nil {

我有一个Go gRPC客户端连接到运行在k8s群集中另一个pod中的gRPC服务器

它工作正常,接收和处理请求

我现在想知道,如果gRPC服务器pod被回收,如何最好地实现恢复能力

据我所知,clientconn.go代码应该自动处理重新连接,但我就是无法让它工作,我担心我的实现在一开始是不正确的

从main调用代码:

go func() {     
        if err := gRPCClient.ProcessRequests(); err != nil {
            log.Error("Error while processing Requests")
            //do something here??
        }
    }()
gRPCClient包装模块中的我的代码:

func (grpcclient *gRPCClient) ProcessRequests() error {
    defer grpcclient.Close()    

    for {
        request, err := reqclient.stream.Recv()
        log.Info("Request received")
        if err == io.EOF {          
            break
        }
        if err != nil {
            //when pod is recycled, this is what's hit with err:
            //rpc error: code = Unavailable desc = transport is closing"

            //what is the correct pattern for recovery here so that we can await connection
            //and continue processing requests once more?
            //should I return err here and somehow restart the ProcessRequests() go routine in the 
            //main funcition?
            break
            
        } else {
            //the happy path
            //code block to process any requests that are received
        }
    }

    return nil
}

func (reqclient *RequestClient) Close() {
//this is called soon after the conneciton drops
        reqclient.conn.Close()
}
编辑: Emin Laletovic在下面优雅地回答了我的问题,并且在大部分过程中都得到了回答。 我必须对waitUntilReady函数进行一些更改:

func (grpcclient *gRPCClient) waitUntilReady() bool {
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Second) //define how long you want to wait for connection to be restored before giving up
defer cancel()

currentState := grpcclient.conn.GetState()
stillConnecting := true

for currentState != connectivity.Ready && stillConnecting {
    //will return true when state has changed from thisState, false if timeout
    stillConnecting = grpcclient.conn.WaitForStateChange(ctx, currentState)
    currentState = grpcclient.conn.GetState()
    log.WithFields(log.Fields{"state: ": currentState, "timeout": timeoutDuration}).Info("Attempting reconnection. State has changed to:")
}

if stillConnecting == false {
    log.Error("Connection attempt has timed out.")
    return false
}

return true
}

RPC连接由
clientconn.go
自动处理,但这并不意味着流也会自动处理

流一旦中断,无论是由于RPC连接中断还是其他原因,都无法自动重新连接,并且一旦RPC连接恢复,您需要从服务器获取新流

等待RPC连接处于
READY
状态并建立新流的伪代码可能如下所示:

func (grpcclient *gRPCClient) ProcessRequests() error {
    defer grpcclient.Close()    
    
    go grpcclient.process()
    for {
      select {
        case <- grpcclient.reconnect:
           if !grpcclient.waitUntilReady() {
             return errors.New("failed to establish a connection within the defined timeout")
           }
           go grpcclient.process()
        case <- grpcclient.done:
          return nil
      }
    }
}

func (grpcclient *gRPCClient) process() {
    reqclient := GetStream() //always get a new stream
    for {
        request, err := reqclient.stream.Recv()
        log.Info("Request received")
        if err == io.EOF {          
            grpcclient.done <- true
            return
        }
        if err != nil {
            grpcclient.reconnect <- true
            return
            
        } else {
            //the happy path
            //code block to process any requests that are received
        }
    }
}

func (grpcclient *gRPCClient) waitUntilReady() bool {
  ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) //define how long you want to wait for connection to be restored before giving up
  defer cancel()
  return grpcclient.conn.WaitForStateChange(ctx, conectivity.Ready)
}
func(grpcclient*grpcclient)ProcessRequests()错误{
延迟grpcclient.Close()
转到grpcclient.process()
为了{
挑选{

感谢您的案例,这让我在大部分方面都做到了。从我的测试来看,waitUntilReady()中存在一个问题,首先WaitForStateChange从提供的状态返回,因此由于状态为TransientFailure,它会立即返回。为了使这项工作正常,我引入了一个for循环,以继续尝试,直到状态变为“就绪”请参阅我的原始帖子了解我的版本。