【问题标题】:Google API Client for .NET: How to implement Exponential Backoff.NET 的 Google API 客户端:如何实现指数退避
【发布时间】:2018-12-06 03:13:30
【问题描述】:

我创建了一种方法,可以使用 .NET 核心和 google 的 .NET 客户端库将批处理请求中的成员添加到 google 组。代码如下所示:

private void InitializeGSuiteDirectoryService()
{
    _directoryServiceCredential = GoogleCredential
        .FromJson(GlobalSettings.Instance.GSuiteSettings.Credentials)
        .CreateScoped(_scopes)
        .CreateWithUser(GlobalSettings.Instance.GSuiteSettings.User);

    _directoryService = new DirectoryService(new  BaseClientService.Initializer()
    {
        HttpClientInitializer = _directoryServiceCredential,
        ApplicationName = _applicationName
    });
}

public OperationResult<int> AddGroupMembers(Group group, IEnumerable<Member> members)
{
    var result = new OperationResult<int>();
    var memberList = members.ToList();
    var batchRequestCount = 0;

    if (memberList.Any())
    {
        var request = new BatchRequest(_directoryService);

        foreach (var member in memberList)
        {
            batchRequestCount++;
            request.Queue<Members>(_directoryService.Members.Insert(member, group.Id), (content, error, i, message) =>
            {
                if (message.IsSuccessStatusCode)
                {
                    //log OK
                }
                else
                {
                    // Implement Exponential backoff only on the request that failed.
                }
            });
            if (batchRequestCount == 30|| member.Equals(memberList.Last()))
            {
                request.ExecuteAsync().Wait();
                request = new BatchRequest(_directoryService); //Clear queue
            }
        }
    }

    return result;
}

如果成员数量很少,逻辑可以正常工作;但是,当成员数为 100 时(这是我的 google 测试实例中的最大用户数),我从 Google 收到一条错误消息,内容为:“quotaExceeded”。根据 Google 的 documentation,他们的 Admin SDK 上的批处理请求限制为 1000,当我们达到 30 的限制时,我已将逻辑设置为执行。

问题是:如何实现错误处理以在收到此错误时重试?他们的文档建议使用包含“可重试错误”的响应来实施“指数退避”(当我检查我的响应时没有看到这一点)。

【问题讨论】:

    标签: google-api google-api-dotnet-client


    【解决方案1】:

    所以这就是我最终在调用将成员添加到 Gsuite 组时实施指数退避的方法。由于我使用的是 dotnet core,因此我能够使用“Polly”,这是一个弹性和瞬态故障处理库,可提供开箱即用的此功能。可能需要重构,但现在的代码如下所示:

        public OperationResult<int> AddGroupMembers(Group group, IEnumerable<Member> members)
        {
            var result = new OperationResult<int>();
            var memberList = members.ToList();
            var batchRequestCount = 0;
    
            if (memberList.Any())
            {
                var request = new BatchRequest(_directoryService);
    
                foreach (var member in memberList)
                {
                    retryRequest = false; // This variable needs to be declared at the class level to guarantee the value is available to the original thread running the process.
                    batchRequestCount++;
                    request.Queue<Members>(_directoryService.Members.Insert(member, group.Id), (content, error, i, message) =>
                    {
                        // If error code is 'quotaExceeded' retry the request ( You can add as many error codes as you'd like to retry here) 
                        if (error.Code == 403)
                        {
                            retryRequest = true;
                        }
    
                    });
    
                    // Execute batch request to add members in batches of 30 member max
                    if (batchRequestCount == 30|| member.Equals(memberList.Last()))
                    {
    
                        // Below is what the code to retry using polly looks like
                        var response = Policy
                            .HandleResult<HttpResponseMessage>(message => message.StatusCode == HttpStatusCode.Conflict)
                            .WaitAndRetry(new[]
                            {
                                TimeSpan.FromSeconds(1),
                                TimeSpan.FromSeconds(2),
                                TimeSpan.FromSeconds(4)
                            }, (results, timeSpan, retryCount, context) =>
                            {
                                // Log Warn saying a retry was required.
                            })
                            .Execute(() =>
                            {
                                var httpResponseMsg = new HttpResponseMessage();
    
                                // Execute batch request Synchronously
                                request.ExecuteAsync().Wait();
                                if (retryRequest)
                                {
                                    httpResponseMsg.StatusCode = HttpStatusCode.Conflict;
                                    retryRequest = false;
                                }
                                else
                                {
                                    httpResponseMsg.StatusCode = HttpStatusCode.OK;
                                }
    
                                return httpResponseMsg;
                            });
                        if (response.IsSuccessStatusCode)
                        {
                           // Log info
                        }
                        else
                        {
                            // Log warn
                        }
    
                        requestCount = 0;
                        request = new BatchRequest(_directoryService);
                        batchCompletedCount++;
                    }
                }
            }
    
            return result;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-04
      • 2020-01-09
      • 2019-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-08
      • 1970-01-01
      相关资源
      最近更新 更多