RPC有超时机制吗?

时间:2014-04-27 22:50:22

标签: go rpc

如果RPC没有超时机制,如果它试图调用已关闭的服务器的RPC方法,如何“终止”RPC调用?

4 个答案:

答案 0 :(得分:7)

您可以使用channels来实现超时模式:

import "time"

c := make(chan error, 1)
go func() { c <- client.Call("Service", args, &result) } ()
select {
  case err := <-c:
    // use err and result
  case <-time.After(timeoutNanoseconds):
    // call timed out
}

select会阻止client.Call返回或timeoutNanoseconds过去。

答案 1 :(得分:2)

如果你想实现超时(以防止呼叫花费太长时间),那么你需要更改net.DialTimeout的rpc.Dial(注意它们是单独的包:rpc vs net)。还要注意返回的类型不再是客户端(如前面的例子中所示);相反,它是一个'连接'。

  conn, err := net.DialTimeout("tcp", "localhost:8080", time.Minute)
  if err != nil {
    log.Fatal("dialing:", err)
  }

  client := rpc.NewClient(conn)

答案 2 :(得分:0)

似乎net / rpc的唯一解决方案是在发现卡住请求时关闭底层连接。然后客户端应该完成待处理的请求,其中&#34;连接断开&#34;错误。

另一种方法是使用https://github.com/valyala/gorpc,它支持开箱即用的超时RPC调用。

答案 3 :(得分:0)

或者,现在不高兴,有人可能更喜欢使用上下文。这还可以确保在超时时返回正确的错误。 (context.DeadlineExceeded

import (
    "context"
    "log"
    "net/rpc"
)

type Client struct {
    *rpc.Client
}

// CallEx is a context aware wrapper around rpc's Client.Call()
func (c *client) CallEx(ctx context.Context, serviceMethod string, args interface{}, reply interface{}) error {
    ec := make(chan error, 1)
    go func() {
        ec <- c.Call(serviceMethod, args, reply)
    }()
    select {
    case err := <-ec:
        return err
    case <-ctx.Done():
        return ctx.Err()
    }
}

在截止日期上下文中调用它:

type Args struct {
   A, B int
}

func main(){
    rpc, err := rpc.DialHTTP("tcp", "host")
    if err != nil {
        t.Fatal(err)
    }
    c := client{rpc}

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    var i int
    if err := c.CallEx(ctx, "Calc.Multiply", Args{2, 2}, &i); err != nil {
        log.Fatal(err)
    }
}