dubbo.apache.org/dubbo-go/v3@v3.1.1/protocol/grpc/grpc_invoker.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package grpc 19 20 import ( 21 "context" 22 "reflect" 23 "sync" 24 ) 25 26 import ( 27 hessian2 "github.com/apache/dubbo-go-hessian2" 28 29 "github.com/dubbogo/gost/log/logger" 30 31 "github.com/pkg/errors" 32 33 "google.golang.org/grpc/connectivity" 34 ) 35 36 import ( 37 "dubbo.apache.org/dubbo-go/v3/common" 38 "dubbo.apache.org/dubbo-go/v3/protocol" 39 ) 40 41 var errNoReply = errors.New("request need @response") 42 43 // nolint 44 type GrpcInvoker struct { 45 protocol.BaseInvoker 46 quitOnce sync.Once 47 clientGuard *sync.RWMutex 48 client *Client 49 } 50 51 // NewGrpcInvoker returns a Grpc invoker instance 52 func NewGrpcInvoker(url *common.URL, client *Client) *GrpcInvoker { 53 return &GrpcInvoker{ 54 BaseInvoker: *protocol.NewBaseInvoker(url), 55 clientGuard: &sync.RWMutex{}, 56 client: client, 57 } 58 } 59 60 func (gi *GrpcInvoker) setClient(client *Client) { 61 gi.clientGuard.Lock() 62 defer gi.clientGuard.Unlock() 63 64 gi.client = client 65 } 66 67 func (gi *GrpcInvoker) getClient() *Client { 68 gi.clientGuard.RLock() 69 defer gi.clientGuard.RUnlock() 70 71 return gi.client 72 } 73 74 // Invoke is used to call service method by invocation 75 func (gi *GrpcInvoker) Invoke(ctx context.Context, invocation protocol.Invocation) protocol.Result { 76 var result protocol.RPCResult 77 78 if !gi.BaseInvoker.IsAvailable() { 79 // Generally, the case will not happen, because the invoker has been removed 80 // from the invoker list before destroy,so no new request will enter the destroyed invoker 81 logger.Warnf("this grpcInvoker is destroyed") 82 result.Err = protocol.ErrDestroyedInvoker 83 return &result 84 } 85 86 gi.clientGuard.RLock() 87 defer gi.clientGuard.RUnlock() 88 89 if gi.client == nil { 90 result.Err = protocol.ErrClientClosed 91 return &result 92 } 93 94 if !gi.BaseInvoker.IsAvailable() { 95 // Generally, the case will not happen, because the invoker has been removed 96 // from the invoker list before destroy,so no new request will enter the destroyed invoker 97 logger.Warnf("this grpcInvoker is destroying") 98 result.Err = protocol.ErrDestroyedInvoker 99 return &result 100 } 101 102 if invocation.Reply() == nil { 103 result.Err = errNoReply 104 } 105 106 var in []reflect.Value 107 in = append(in, reflect.ValueOf(ctx)) 108 in = append(in, invocation.ParameterValues()...) 109 110 methodName := invocation.MethodName() 111 method := gi.client.invoker.MethodByName(methodName) 112 res := method.Call(in) 113 114 result.Rest = res[0] 115 // check err 116 if !res[1].IsNil() { 117 result.Err = res[1].Interface().(error) 118 } else { 119 _ = hessian2.ReflectResponse(res[0], invocation.Reply()) 120 } 121 122 return &result 123 } 124 125 // IsAvailable get available status 126 func (gi *GrpcInvoker) IsAvailable() bool { 127 client := gi.getClient() 128 if client != nil { 129 return gi.BaseInvoker.IsAvailable() && client.GetState() != connectivity.Shutdown 130 } 131 132 return false 133 } 134 135 // IsDestroyed get destroyed status 136 func (gi *GrpcInvoker) IsDestroyed() bool { 137 client := gi.getClient() 138 if client != nil { 139 return gi.BaseInvoker.IsDestroyed() && client.GetState() == connectivity.Shutdown 140 } 141 142 return false 143 } 144 145 // Destroy will destroy gRPC's invoker and client, so it is only called once 146 func (gi *GrpcInvoker) Destroy() { 147 gi.quitOnce.Do(func() { 148 gi.BaseInvoker.Destroy() 149 client := gi.getClient() 150 if client != nil { 151 gi.setClient(nil) 152 client.Close() 153 } 154 }) 155 }