func RetryKVClient(c *Client) pb.KVClient {
	retryWrite := &retryWriteKVClient{pb.NewKVClient(c.conn), c.retryWrapper}
	return &retryKVClient{&retryWriteKVClient{retryWrite, c.retryAuthWrapper}}
}
RetryKVClient implements a KVClient that uses the client's FailFast retry policy.
package clientv3
import (
	"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
)
type rpcFunc func(ctx context.Context) error
type retryRpcFunc func(context.Context, rpcFunc) error
func (c *Client) newRetryWrapper() retryRpcFunc {
	return func(rpcCtx context.Context, f rpcFunc) error {
		for {
			err := f(rpcCtx)
			if err == nil {
				return nil
			}
			eErr := rpctypes.Error(err)
			if _, ok := eErr.(rpctypes.EtcdError); ok {
				return err
			}
			if grpc.Code(err) != codes.Unavailable {
				return err
			}
			select {
			case <-c.balancer.ConnectNotify():
			case <-rpcCtx.Done():
				return rpcCtx.Err()
			case <-c.ctx.Done():
				return c.ctx.Err()
			}
		}
	}
}
func (c *Client) newAuthRetryWrapper() retryRpcFunc {
	return func(rpcCtx context.Context, f rpcFunc) error {
		for {
			err := f(rpcCtx)
			if err == nil {
				return nil
			}
			if rpctypes.Error(err) == rpctypes.ErrInvalidAuthToken {
				gterr := c.getToken(rpcCtx)
				if gterr != nil {
					return err  
				}
				continue
			}
			return err
		}
	}
}