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. 详解PNG文件结构

    前言 PNG,JPEG,GIF,BMP作为数据压缩文件,有许多重要的信息我们需要区深度解析. 一.PNG的文件结构 1.1.数据块构成结构 PNG文件结构很简单,主要有数据块(Chunk Block) ...

  2. C语言关键字register、extern、static、一些总结,及项目中使用的心得

    首先介绍两个概念: 一.变量的生存周期: 变量从建立到撤销的时间段成变量的生存周期.静态变量,从变量产生到整个程序执行结束.当函数使用变量结束后,变量的存储空间依然存在,变量的值也会随着函数的对其的使 ...

  3. IEEE发布2017年编程语言排行榜:Python高居首位

    https://news.cnblogs.com/n/574248 编者按:本文由微信公众号“机器之心”(ID:almosthuman2014)编译,机器之心专注生产 AI 领域专业性内容.本文作者: ...

  4. Ocelot中文文档-服务发现

    Ocelot允许您指定服务发现提供程序,并使用它来查找Ocelot正在将请求转发给下游服务的主机和端口.目前,这仅在GlobalConfiguration部分中受支持,这意味着所有ReRoute将使用 ...

  5. Mysql分页查询性能分析

    [PS:原文手打,转载说明出处,博客园] 前言 看过一堆的百度,最终还是自己做了一次实验,本文基于Mysql5.7.17版本,Mysql引擎为InnoDB,编码为utf8,排序规则为utf8_gene ...

  6. 微信小程序-框架详解(1)

    配置 -app.json文件对微信小程序进行全局配置,决定页面文件的路径.窗口表现.设置网络超时时间.tab等 { "pages": [ //决定页面文件的路径 "pag ...

  7. 基于opencv下对视频的灰度变换,高斯滤波,canny边缘检测处理,同窗体显示并保存

    如题:使用opencv打开摄像头或视频文件,实时显示原始视频,将视频每一帧依次做灰度转换.高斯滤波.canny边缘检测处理(原始视频和这3个中间步骤处理结果分别在一个窗口显示),最后将边缘检测结果保存 ...

  8. Java多线程:wait(),notify(),notifyAll()

    1. wait(),notify(),notifyAll() 2. wait() 2.1. wait() 2.2. wait(long timeout) 2.3. wait(long timeout, ...

  9. 分析DuxCms之AdminController

    /** * 后台模板显示 调用内置的模板引擎显示方法, * @access protected * @param string $templateFile 指定要调用的模板文件 * @return v ...

  10. python_字典 list_4

    >>> import string>>> import random #组合字符>>> x=string.ascii_letters+string ...