|
@@ -9,47 +9,50 @@ import (
|
|
|
)
|
|
|
|
|
|
type Client struct {
|
|
|
- selector *registry.Selector
|
|
|
- clientLocker sync.RWMutex
|
|
|
- clients map[string]*rpc.Client
|
|
|
+ selector *registry.Selector
|
|
|
+ clients sync.Map
|
|
|
+ once sync.Once
|
|
|
}
|
|
|
|
|
|
func (c *Client) Do(ctx context.Context, r *Request) (resp Response, err error) {
|
|
|
var (
|
|
|
ok bool
|
|
|
node *registry.ServiceNode
|
|
|
+ value interface{}
|
|
|
client *rpc.Client
|
|
|
)
|
|
|
- c.clientLocker.RLock()
|
|
|
- client, ok = c.clients[r.ServiceName]
|
|
|
- c.clientLocker.RUnlock()
|
|
|
+ value, ok = c.clients.Load(r.ServiceName)
|
|
|
if ok {
|
|
|
+ client = value.(*rpc.Client)
|
|
|
goto _EXEC
|
|
|
}
|
|
|
if node, err = c.selector.Select(ctx, r.ServiceName); err != nil {
|
|
|
return
|
|
|
}
|
|
|
client = rpc.NewClient()
|
|
|
- if err = client.Dialer("tcp", fmt.Sprintf("%s:%d", node.Address, node.Port)); err != nil {
|
|
|
+ if err = client.DialerContext(ctx, "tcp", fmt.Sprintf("%s:%d", node.Address, node.Port)); err != nil {
|
|
|
return
|
|
|
}
|
|
|
+ c.clients.Store(r.ServiceName, client)
|
|
|
_EXEC:
|
|
|
- return client.Do(ctx, rpc.NewRequest(r.Method, r.Body))
|
|
|
+ if resp, err = client.Do(ctx, rpc.NewRequest(r.Method, r.Body)); err != nil {
|
|
|
+ c.clients.Delete(r.ServiceName)
|
|
|
+ }
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
func (c *Client) Close() (err error) {
|
|
|
- c.clientLocker.Lock()
|
|
|
- defer c.clientLocker.Unlock()
|
|
|
- for name, client := range c.clients {
|
|
|
+ c.clients.Range(func(key, value interface{}) bool {
|
|
|
+ client := value.(*rpc.Client)
|
|
|
_ = client.Close()
|
|
|
- delete(c.clients, name)
|
|
|
- }
|
|
|
+ c.clients.Delete(key)
|
|
|
+ return true
|
|
|
+ })
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func NewClient(reg registry.Registry) *Client {
|
|
|
return &Client{
|
|
|
- clients: make(map[string]*rpc.Client),
|
|
|
selector: registry.NewSelector(reg),
|
|
|
}
|
|
|
}
|