0

问题

我正在使用google-api-objectivec-client库来使用 Google Drive API。
我正在appDataFolder(例如)内部创建 10 个文件夹,没有任何延迟,而且速度太快,而且我不断收到9/10的请求错误:

Error Domain=com.google.GTLJSONRPCErrorDomain Code=500 "(Internal Error)" UserInfo={error=Internal Error, NSLocalizedFailureReason=(Internal Error)

some times these:
Error Domain=com.google.GTLJSONRPCErrorDomain Code=403 "(User Rate Limit Exceeded)" UserInfo={error=User Rate Limit Exceeded, NSLocalizedFailureReason=(User Rate Limit Exceeded),

很可能,它与“垃圾邮件”userRateLimit异常有关,因为它可以通过“睡眠”轻松修复(已多次复制)。

建议的解决方案

谷歌建议用这种错误重试请求,即使它提供了很好的 API 来自动完成。根据文件

GTL 服务类和 GTMSessionFetcher 类提供了一种机制,用于自动重试一些常见的网络和服务器错误,并适当增加每次尝试之间的延迟。您可以通过设置 retryEnabled 属性打开对 GTL 服务的自动重试支持。

// Turn on automatic retry of some common error results
service.retryEnabled = YES;

重试的默认错误为 http 状态 408(请求超时)、503(服务不可用)和 504(网关超时)、NSURLErrorNetworkConnectionLost 和 NSURLErrorTimedOut。您可以指定除默认值 1 分钟以外的最大重试间隔,并且可以提供可选的重试选择器来自定义每次重试尝试的条件。

但是状态为 500 的错误不在默认列表中。所以,我试着用这个:

// Retry selector is optional for retries.
// If present, it should have the signature:
//   -(BOOL)ticket:(GTLServiceTicket *)ticket willRetry:(BOOL)suggestedWillRetry forError:(NSError *)error
// and return YES to cause a retry.  Note that unlike the fetcher retry
// selector, this selector's first argument is a ticket, not a fetcher.

GTLService.retrySelector

我创建了一个不断返回的方法YES,但它永远不会被调用,因此不会重试有错误的请求。

问题

如何使用自动重试google-api-objectivec-client

更新。重现问题的代码示例:

- (void) reproduceTheIssue: (GTMOAuth2Authentication *) authorizer {

    GTLServiceDrive * driveService = [[GTLServiceDrive alloc] init];
    driveService.retryEnabled = true;
    driveService.authorizer = authorizer;
    //    driveService.fetcherService.retryEnabled = YES; //this also doesn't help
    //    driveService.retrySelector =  @selector(ticket:willRetry:forError:);
    const int DELAY = 0;
    const int NUMBER_OF_FOLDERS = 50;

    for (int i = 0; i < NUMBER_OF_FOLDERS; i++) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, DELAY * NSEC_PER_SEC), dispatch_get_main_queue(), ^{

            GTLDriveFile * nestedFolder = [GTLDriveFile object];
            NSString * folderName = [NSString stringWithFormat: @"folder-number-%i", i];
            nestedFolder.name = folderName;
            nestedFolder.mimeType = @"application/vnd.google-apps.folder";
            nestedFolder.parents = @[@"appDataFolder"];

            GTLQueryDrive * query = [GTLQueryDrive queryForFilesCreateWithObject: nestedFolder uploadParameters: nil];
            [driveService executeQuery: query completionHandler: ^(GTLServiceTicket * ticket, GTLDriveFile * updatedFile, NSError * error) {
                if (error == nil) {
                    NSLog(@"Successfully created a folder %@", updatedFile);
                } else {
                    NSLog(@"Failed to a folder: %@ error: %@", folderName, error);
                }
            }];
        });
    }
}

- (BOOL) ticket: (GTLServiceTicket *) ticket willRetry: (BOOL) suggestedWillRetry forError: (NSError *) error {
    NSLog(@"I will never be called :( with this arguments ticket: %@, willRetry: %i, error :%@", ticket, suggestedWillRetry, error);
    return YES;
}

更新更新该问题在图书馆的 GitHub 上进行了讨论。简短回答:无法自动重试这些错误。它应该由用户以编程方式管理handlers

重试逻辑位于 http fetcher 类中,因此重试仅反映网络请求期间出现的错误。

4

0 回答 0