问题
我正在使用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 类中,因此重试仅反映网络请求期间出现的错误。