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. 从ruby实现时间服务器ntp同步功能也谈“逆向工程”

    本猫以前写asm和C的时候常常不忘"逆向"一把,后来写驱动的时候也用VM之类的搭建"双机"调试环境进行调试:也对于一些小的软件crack cd-key神马的不亦 ...

  2. 简单了解JS中的几种遍历

    忙了好一段时间,项目上线后终于有那么一点点空档期静下来整理一些问题了.当我们在开发项目的时候,用到遍历的地方肯定少不了,那么我们有那么多的遍历方法,在不同情况下用那种方法会更优雅而且还没bug呢? 首 ...

  3. 如何卸载Centos自带jdk

    1.搜索安装的jdk: rpm -qa|grep jdk 结果如下: java-1.7.0-openjdk-1.7.0.45-2.4.3.3.el6.x86_64 java-1.6.0-openjdk ...

  4. WSL Windows Subsystem for Linux安装指南

    见官方文档: https://msdn.microsoft.com/en-us/commandline/wsl/install_guide

  5. 竞品调研时发现的Android新设计特性

    先share两篇技术层面的文章: Android M新控件之FloatingActionButton,TextInputLayout,Snackbar,TabLayout的使用:http://blog ...

  6. goquery 添加header 发起请求

    goquery 添加header 发起请求 我们知道使用net/http 很容易发起GET or POST 请求:并且在发起http请求时候,可以很容易的对header进行干预 例如: client ...

  7. Grunt的配置和使用

    Grunt和Grunt插件是通过NodeJs的包管理工具npm安装并进行管理的. Grunt 0.4.x必须配合NodeJs=>0.8.0版本使用(奇数版本的NodeJs不是稳定的开发版本)   ...

  8. Java开源生鲜电商平台-系统架构与技术选型(源码可下载)

    Java开源生鲜电商平台-系统架构与技术选型(源码可下载) 1.  硬件环境 公司服务器 2.   软件环境 2.1  操作系统 Linux CentOS 6.8系列 2.2 反向代理/web服务器 ...

  9. Scala编程入门---面向对象编程之Trait高级知识

    trait调用链 Scala中支持让类继承多个Trait后,依次调用多个Trait中的同一个方法,只要让多个trait的同一个方法中,在最后都执行super.方法即可 类中调用多个trait中都有这个 ...

  10. hive 分组排序,topN

    hive 分组排序,topN 语法格式:row_number() OVER (partition by COL1 order by COL2 desc ) rankpartition by:类似hiv ...