【发布时间】:2014-06-13 08:18:50
【问题描述】:
如果 RPC 没有超时机制,如果 RPC 调用试图调用已关闭服务器的 RPC 方法,我该如何“杀死”它?
【问题讨论】:
如果 RPC 没有超时机制,如果 RPC 调用试图调用已关闭服务器的 RPC 方法,我该如何“杀死”它?
【问题讨论】:
您可以使用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 过去。
【讨论】:
似乎 net/rpc 的唯一解决方案是在您发现卡住的请求时关闭底层连接。然后客户端应该完成挂起的请求,出现“连接中断”错误。
另一种方法是使用 https://github.com/valyala/gorpc ,它支持开箱即用的超时 RPC 调用。
【讨论】:
如果您想实现超时(以防止调用时间过长),那么您需要将 rpc.Dial 更改为 net.DialTimeout(注意它们是单独的包:rpc 与 net)。另请注意,返回的类型不再是客户端(就像在前面的示例中一样);相反,它是一个“连接”。
conn, err := net.DialTimeout("tcp", "localhost:8080", time.Minute)
if err != nil {
log.Fatal("dialing:", err)
}
client := rpc.NewClient(conn)
【讨论】:
或者,现在,有人可能更喜欢使用上下文。这还负责在超时时返回正确的错误。 (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()
}
}
使用 Deadlined 上下文调用它:
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)
}
}
【讨论】: