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. java中内存的使用

    一个java运行起来执行代码,主要的内存消耗有这几块: 1.堆 2.栈 :栈是每个线程一个的,是以消耗的内存是内存大小*线程数,当线程数特多时候需要小心 . 3.直接内存:主要是通道时候的缓存,在内存 ...

  2. WebService技术简介

    今天继续阅读<.Net 大局观>时看到一段关于WebService支持技术的论述,真是简明扼要: Web services的另一个重要应用是B2B整合,一般来说它也依赖Internet,将 ...

  3. Day9 进程同步锁 进程队列 进程池 生产消费模型 进程池 paramike模块

    进程同步锁: 当运行程序的时候,有可能你的程序同时开多个进程,开进程的时候会将多个执行结果打印出来,这样的话打印的信息都是错乱的,怎么保证打印信息是有序的呢? 其实也就是相当于让进程独享资源. fro ...

  4. 装修工人如何在网上"找活"

    http://blog.sina.com.cn/s/blog_555e8fe80102wwsz.html ps:其实码农也是一种装修工. 在这个互联网时代,各个行业都在利用网络达到自己的商业目的,作为 ...

  5. Android弹幕功能实现,模仿斗鱼直播的弹幕效果

    转载出处:http://blog.csdn.net/sinyu890807/article/details/51933728 本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即 ...

  6. OkHttp上传文件,服务器端请求解析找不到文件信息的问题

    长话短说,不深入解释了,官方给的上传案例代码: private static final String IMGUR_CLIENT_ID = "..."; private stati ...

  7. springboot中使用分页,文件上传,jquery的具体步骤(持续更新)

    分页: pom.xml     加依赖 <dependency> <groupId>com.github.pagehelper</groupId> <arti ...

  8. JDBC连接数据库时候出错

    错误提示如下: Fri May 13 09:06:04 CST 2016 WARN: Establishing SSL connection without server's identity ver ...

  9. erlang的脚本执行---escript

    1.概述: 作为程序员对于脚本语言应该很熟悉了,脚本语言的优点很多,如快速开发.容易编写.实时开发和执行, 我们常用的脚本有Javascript.shell.python等,我们的erlang语言也有 ...

  10. java监听器之实现在线人数显示

    在码农的世界里只有bug才能让人成长,The more bugs you encounter, the more efficient you will be! java中的监听器分为三种:Servle ...