Skip to content

Commit

Permalink
add ability to distinguish rpc errors
Browse files Browse the repository at this point in the history
  • Loading branch information
lanzafame committed Jun 20, 2018
1 parent ae156c4 commit 64a2d09
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 34 deletions.
41 changes: 33 additions & 8 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,17 +227,23 @@ func checkMatchingLengths(l ...int) bool {
// makeCall decides if a call can be performed. If it's a local
// call it will use the configured server if set.
func (c *Client) makeCall(call *Call) {
logger.Debugf("makeCall: %s.%s",
logger.Debugf(
"makeCall: %s.%s",
call.SvcID.Name,
call.SvcID.Method)
call.SvcID.Method,
)

// Handle local RPC calls
if call.Dest == "" || call.Dest == c.host.ID() {
logger.Debugf("local call: %s.%s",
call.SvcID.Name, call.SvcID.Method)
logger.Debugf(
"local call: %s.%s",
call.SvcID.Name,
call.SvcID.Method,
)
if c.server == nil {
err := errors.New(
"Cannot make local calls: server not set")
"Cannot make local calls: server not set",
)
call.doneWithError(err)
return
}
Expand Down Expand Up @@ -294,8 +300,12 @@ func (c *Client) send(call *Call) {

// receiveResponse reads a response to an RPC call
func receiveResponse(s *streamWrap, call *Call) {
logger.Debugf("waiting response for %s.%s to %s", call.SvcID.Name,
call.SvcID.Method, call.Dest)
logger.Debugf(
"waiting response for %s.%s to %s",
call.SvcID.Name,
call.SvcID.Method,
call.Dest,
)
var resp Response
if err := s.dec.Decode(&resp); err != nil {
call.doneWithError(err)
Expand All @@ -305,7 +315,7 @@ func receiveResponse(s *streamWrap, call *Call) {

defer call.done()
if e := resp.Error; e != "" {
call.setError(errors.New(e))
call.setError(&nonRPCError{e})
}

// Even on error we sent the reply so it needs to be
Expand All @@ -315,3 +325,18 @@ func receiveResponse(s *streamWrap, call *Call) {
}
return
}

type nonRPCError struct {
msg string
}

func (n *nonRPCError) Error() string {
return n.msg
}

func (c *Client) IsRPCError(err error) bool {
if _, ok := err.(*nonRPCError); ok {
return false
}
return true
}
21 changes: 14 additions & 7 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,19 @@ func (server *Server) Call(call *Call) error {
if reflect.TypeOf(call.Args).Kind() != reflect.Ptr {
return fmt.Errorf(
"%s.%s is being called with the wrong arg type",
call.SvcID.Name, call.SvcID.Method)
call.SvcID.Name,
call.SvcID.Method,
)
}
argv = reflect.New(mtype.ArgType.Elem())
argv.Elem().Set(reflect.ValueOf(call.Args).Elem())
} else {
if reflect.TypeOf(call.Args).Kind() == reflect.Ptr {
return fmt.Errorf(
"%s.%s is being called with the wrong arg type",
call.SvcID.Name, call.SvcID.Method)
call.SvcID.Name,
call.SvcID.Method,
)
}
argv = reflect.New(mtype.ArgType)
argv.Elem().Set(reflect.ValueOf(call.Args))
Expand All @@ -282,11 +286,14 @@ func (server *Server) Call(call *Call) error {
// Call service and respond
function := mtype.method.Func
// Invoke the method, providing a new value for the reply.
returnValues := function.Call([]reflect.Value{
service.rcvr,
ctxv, // context
argv, // argument
replyv}) // reply
returnValues := function.Call(
[]reflect.Value{
service.rcvr,
ctxv, // context
argv, // argument
replyv,
},
) // reply

creplyv := reflect.ValueOf(call.Reply)
creplyv.Elem().Set(replyv.Elem())
Expand Down
52 changes: 33 additions & 19 deletions server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,26 +210,40 @@ func TestErrorResponse(t *testing.T) {
var arith Arith
s.Register(&arith)

var r int
// test remote
c := NewClientWithServer(h2, "rpc", s)
err := c.Call(h1.ID(), "Arith", "GimmeError", &Args{1, 2}, &r)
if err == nil || err.Error() != "an error" {
t.Error("expected different error")
}
if r != 42 {
t.Error("response should be set even on error")
}
t.Run("remote", func(t *testing.T) {
var r int
c := NewClientWithServer(h2, "rpc", s)
err := c.Call(h1.ID(), "Arith", "GimmeError", &Args{1, 2}, &r)
if err == nil || err.Error() != "an error" {
t.Error("expected different error")
}
if r != 42 {
t.Error("response should be set even on error")
}
})

// test local
c = NewClientWithServer(h1, "rpc", s)
err = c.Call(h1.ID(), "Arith", "GimmeError", &Args{1, 2}, &r)
if err == nil || err.Error() != "an error" {
t.Error("expected different error")
}
if r != 42 {
t.Error("response should be set even on error")
}
t.Run("test non rpc error", func(t *testing.T) {
var r int
c := NewClientWithServer(h2, "rpc", s)
err := c.Call(h1.ID(), "Arith", "ThisIsNotAMethod", &Args{1, 2}, &r)
if err != nil {
if c.IsRPCError(err) {
t.Error("expected non rpc error")
}
}
})

t.Run("local", func(t *testing.T) {
var r int
c := NewClientWithServer(h1, "rpc", s)
err := c.Call(h1.ID(), "Arith", "GimmeError", &Args{1, 2}, &r)
if err == nil || err.Error() != "an error" {
t.Error("expected different error")
}
if r != 42 {
t.Error("response should be set even on error")
}
})
}

func testCallContext(t *testing.T, servHost, clientHost host.Host, dest peer.ID) {
Expand Down

0 comments on commit 64a2d09

Please sign in to comment.