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
            }

            // only retry if unavailable
            if grpc.Code(err) != codes.Unavailable {
                return err
            }
            // always stop retry on etcd errors
            eErr := rpctypes.Error(err)
            if _, ok := eErr.(rpctypes.EtcdError); ok {
                return err
            }

            select {
            case <-c.balancer.ConnectNotify():
            case <-rpcCtx.Done():
                return rpcCtx.Err()
            case <-c.ctx.Done():
                return c.ctx.Err()
            }
        }
    }
}

type retryKVClient struct {
    pb.KVClient
    retryf retryRpcFunc
}

// RetryKVClient implements a KVClient that uses the client's FailFast retry policy.
func RetryKVClient(c *Client) pb.KVClient {
    return &retryKVClient{pb.NewKVClient(c.conn), c.retryWrapper}
}

func (rkv *retryKVClient) Put(ctx context.Context, in *pb.PutRequest, opts ...grpc.CallOption) (resp *pb.PutResponse, err error) {
    err = rkv.retryf(ctx, func(rctx context.Context) error {
        resp, err = rkv.KVClient.Put(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rkv *retryKVClient) DeleteRange(ctx context.Context, in *pb.DeleteRangeRequest, opts ...grpc.CallOption) (resp *pb.DeleteRangeResponse, err error) {
    err = rkv.retryf(ctx, func(rctx context.Context) error {
        resp, err = rkv.KVClient.DeleteRange(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rkv *retryKVClient) Txn(ctx context.Context, in *pb.TxnRequest, opts ...grpc.CallOption) (resp *pb.TxnResponse, err error) {
    err = rkv.retryf(ctx, func(rctx context.Context) error {
        resp, err = rkv.KVClient.Txn(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rkv *retryKVClient) Compact(ctx context.Context, in *pb.CompactionRequest, opts ...grpc.CallOption) (resp *pb.CompactionResponse, err error) {
    err = rkv.retryf(ctx, func(rctx context.Context) error {
        resp, err = rkv.KVClient.Compact(rctx, in, opts...)
        return err
    })
    return resp, err
}

type retryLeaseClient struct {
    pb.LeaseClient
    retryf retryRpcFunc
}

// RetryLeaseClient implements a LeaseClient that uses the client's FailFast retry policy.
func RetryLeaseClient(c *Client) pb.LeaseClient {
    return &retryLeaseClient{pb.NewLeaseClient(c.conn), c.retryWrapper}
}

func (rlc *retryLeaseClient) LeaseGrant(ctx context.Context, in *pb.LeaseGrantRequest, opts ...grpc.CallOption) (resp *pb.LeaseGrantResponse, err error) {
    err = rlc.retryf(ctx, func(rctx context.Context) error {
        resp, err = rlc.LeaseClient.LeaseGrant(rctx, in, opts...)
        return err
    })
    return resp, err

}

func (rlc *retryLeaseClient) LeaseRevoke(ctx context.Context, in *pb.LeaseRevokeRequest, opts ...grpc.CallOption) (resp *pb.LeaseRevokeResponse, err error) {
    err = rlc.retryf(ctx, func(rctx context.Context) error {
        resp, err = rlc.LeaseClient.LeaseRevoke(rctx, in, opts...)
        return err
    })
    return resp, err
}

type retryClusterClient struct {
    pb.ClusterClient
    retryf retryRpcFunc
}

// RetryClusterClient implements a ClusterClient that uses the client's FailFast retry policy.
func RetryClusterClient(c *Client) pb.ClusterClient {
    return &retryClusterClient{pb.NewClusterClient(c.conn), c.retryWrapper}
}

func (rcc *retryClusterClient) MemberAdd(ctx context.Context, in *pb.MemberAddRequest, opts ...grpc.CallOption) (resp *pb.MemberAddResponse, err error) {
    err = rcc.retryf(ctx, func(rctx context.Context) error {
        resp, err = rcc.ClusterClient.MemberAdd(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rcc *retryClusterClient) MemberRemove(ctx context.Context, in *pb.MemberRemoveRequest, opts ...grpc.CallOption) (resp *pb.MemberRemoveResponse, err error) {
    err = rcc.retryf(ctx, func(rctx context.Context) error {
        resp, err = rcc.ClusterClient.MemberRemove(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rcc *retryClusterClient) MemberUpdate(ctx context.Context, in *pb.MemberUpdateRequest, opts ...grpc.CallOption) (resp *pb.MemberUpdateResponse, err error) {
    err = rcc.retryf(ctx, func(rctx context.Context) error {
        resp, err = rcc.ClusterClient.MemberUpdate(rctx, in, opts...)
        return err
    })
    return resp, err
}

type retryAuthClient struct {
    pb.AuthClient
    retryf retryRpcFunc
}

// RetryAuthClient implements a AuthClient that uses the client's FailFast retry policy.
func RetryAuthClient(c *Client) pb.AuthClient {
    return &retryAuthClient{pb.NewAuthClient(c.conn), c.retryWrapper}
}

func (rac *retryAuthClient) AuthEnable(ctx context.Context, in *pb.AuthEnableRequest, opts ...grpc.CallOption) (resp *pb.AuthEnableResponse, err error) {
    err = rac.retryf(ctx, func(rctx context.Context) error {
        resp, err = rac.AuthClient.AuthEnable(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rac *retryAuthClient) AuthDisable(ctx context.Context, in *pb.AuthDisableRequest, opts ...grpc.CallOption) (resp *pb.AuthDisableResponse, err error) {
    err = rac.retryf(ctx, func(rctx context.Context) error {
        resp, err = rac.AuthClient.AuthDisable(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rac *retryAuthClient) UserAdd(ctx context.Context, in *pb.AuthUserAddRequest, opts ...grpc.CallOption) (resp *pb.AuthUserAddResponse, err error) {
    err = rac.retryf(ctx, func(rctx context.Context) error {
        resp, err = rac.AuthClient.UserAdd(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rac *retryAuthClient) UserDelete(ctx context.Context, in *pb.AuthUserDeleteRequest, opts ...grpc.CallOption) (resp *pb.AuthUserDeleteResponse, err error) {
    err = rac.retryf(ctx, func(rctx context.Context) error {
        resp, err = rac.AuthClient.UserDelete(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rac *retryAuthClient) UserChangePassword(ctx context.Context, in *pb.AuthUserChangePasswordRequest, opts ...grpc.CallOption) (resp *pb.AuthUserChangePasswordResponse, err error) {
    err = rac.retryf(ctx, func(rctx context.Context) error {
        resp, err = rac.AuthClient.UserChangePassword(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rac *retryAuthClient) UserGrantRole(ctx context.Context, in *pb.AuthUserGrantRoleRequest, opts ...grpc.CallOption) (resp *pb.AuthUserGrantRoleResponse, err error) {
    err = rac.retryf(ctx, func(rctx context.Context) error {
        resp, err = rac.AuthClient.UserGrantRole(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rac *retryAuthClient) UserRevokeRole(ctx context.Context, in *pb.AuthUserRevokeRoleRequest, opts ...grpc.CallOption) (resp *pb.AuthUserRevokeRoleResponse, err error) {
    err = rac.retryf(ctx, func(rctx context.Context) error {
        resp, err = rac.AuthClient.UserRevokeRole(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rac *retryAuthClient) RoleAdd(ctx context.Context, in *pb.AuthRoleAddRequest, opts ...grpc.CallOption) (resp *pb.AuthRoleAddResponse, err error) {
    err = rac.retryf(ctx, func(rctx context.Context) error {
        resp, err = rac.AuthClient.RoleAdd(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rac *retryAuthClient) RoleDelete(ctx context.Context, in *pb.AuthRoleDeleteRequest, opts ...grpc.CallOption) (resp *pb.AuthRoleDeleteResponse, err error) {
    err = rac.retryf(ctx, func(rctx context.Context) error {
        resp, err = rac.AuthClient.RoleDelete(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rac *retryAuthClient) RoleGrantPermission(ctx context.Context, in *pb.AuthRoleGrantPermissionRequest, opts ...grpc.CallOption) (resp *pb.AuthRoleGrantPermissionResponse, err error) {
    err = rac.retryf(ctx, func(rctx context.Context) error {
        resp, err = rac.AuthClient.RoleGrantPermission(rctx, in, opts...)
        return err
    })
    return resp, err
}

func (rac *retryAuthClient) RoleRevokePermission(ctx context.Context, in *pb.AuthRoleRevokePermissionRequest, opts ...grpc.CallOption) (resp *pb.AuthRoleRevokePermissionResponse, err error) {
    err = rac.retryf(ctx, func(rctx context.Context) error {
        resp, err = rac.AuthClient.RoleRevokePermission(rctx, in, opts...)
        return err
    })
    return resp, err
}

retry.go的更多相关文章

  1. 第3月第21天 nsclassfromstring返回null SVN报错:clean the working copy and then retry the operation

    1. xcodeproj工程损坏时,.m文件没有加入编译. 2. SVN报错:clean the working copy and then retry the operation http://bl ...

  2. -bash: fork: retry: Resource temporarily unavailable

    登陆不了服务器The server refused to start a shell. 登陆服务器后执行ls命令报错:   1 2 $ls -bash: fork: retry: Resource t ...

  3. java function retry wrapper

    import java.util.concurrent.Callable; /** * Created by huahui.yang on 1/29/16. */ public class Retry ...

  4. Spring retry基本使用

    Spring retry基本使用 背景介绍 在实际工作过程中,重试是一个经常使用的手段.比如MQ发送消息失败,会采取重试手段,比如工程中使用RPC请求外部服务,可能因为网络 波动出现超时而采取重试手段 ...

  5. freebsd启动报错:My unqualified host name unkown...Sleeping for retry.

    原文 http://blog.163.com/sujoe_2006/blog/static/335315120111158576591/ 病状:启动报"My unqualified host ...

  6. ebs R12.2启动报错"failed to start a managed process after the maximum retry limit"

    启动日志: Error --> Process (index=1,uid=1739599208,pid=4479) failed to start a managed process after ...

  7. Windows Azure Storage 之 Retry Policy (用来处理短暂性错误-Transient Fault)

    在使用Windows Azure Storage Service 的时候, 通常会遇到各种各样的问题. 例如网络连接不稳定,导致请求没有发出去.删除一个Blob Container 之后又立刻创建同名 ...

  8. 启动受管服务器出现:unable to get file lock, will retry...

    启动受管服务器出现:unable to get file lock, will retry... 解决方法:一.删掉Domain下的*.lok文件1. 删除edit.lok进入到domain_home ...

  9. spring retry 使用

    1.  场景      系统方法调用时无状态的,同时因为网络原因,或者系统暂时故障,进行的重试 2. maven 依赖 <project xmlns="http://maven.apa ...

  10. C# Retry重试操作解决方案(附源码)

    一.前言 (1)对于Thread的Abort方法,如果线程当前正在执行的是一段非托管代码,那么CLR就不会抛出ThreadAbortException,只有当代码继续回到CLR中时,才会引发Threa ...

随机推荐

  1. windows下nginx+php

    nginx能够为Web服务器节省资源,相较于我们熟悉的apache.IIS的优势,在于"反向代理"和"负载均衡".那在windows下如何来配置nginx+ph ...

  2. JS(面试中的变量类型和计算问题)

    JS(变量类型和计算) 题目1.JS 中使用 typeof 能得到那些类型? 题目2.何时使用 === 何时使用==? 题目3.JS 中有哪些内置函数? 题目4.JS 变量按照存储方式区分为那些类型, ...

  3. Runtime - ③ - 分类Category探究

    写博客只是为了让自己学的更深刻,参考:https://tech.meituan.com/DiveIntoCategory.html 分类(Category)是个啥玩意儿这里就不多介绍了,这里主要是研究 ...

  4. angular中的jqLite的基本使用方法

    angular.element() 参数要求是HTML string or DOMElement, angular.element 虽然很接近 jQuery,但是直接通过 HTML tag 去获取元素 ...

  5. Thinkphp3.2简单解决多文件上传只上传一张的问题

    html简单页面: index.html代码: <form action="{:U('index/upload')}" method="post" enc ...

  6. AVL树之 Java的实现

    AVL树的介绍 AVL树是高度平衡的而二叉树.它的特点是:AVL树中任何节点的两个子树的高度最大差别为1. 上面的两张图片,左边的是AVL树,它的任何节点的两个子树的高度差别都<=1:而右边的不 ...

  7. Oracle官方文档学习路线图

  8. 集群中几种session同步解决方案的比较[转]

    集群中session安全和同步是个最大的问题,下面是我收集到的几种session同步的方案,希望能通过分析其各自的优劣找出其适应的场景. 1. 客户端cookie加密 这是我以前采用的方式,简单,高效 ...

  9. SQL遇到的问题

    1.问题描述:拼接sql字符串涉及到表变量时报错.  解决办法:把表变量的定义一同放在字符串中. 2.问题描述:EF添加实体后,调用存储过程调用不到 解决办法:必须先db.SaveChanges()后 ...

  10. Centos 如何 发布Java项目

    在发布Java项目之前,我们先要安装如下软件 一.Windows 1.winscp(Windows到centos上传下载) 2.PuTTY(Windows访问centos服务器) 3.Navicat客 ...