4

我有一个驱动器应用程序,它请求所有未丢弃的文件。但有时它会引发读取超时的 IOexception。有没有办法避免这种情况?

这是我得到的错误:

发生错误:java.net.SocketTimeoutException:读取超时

也许我的指数退避实施错误。

这是我用来获取文件的代码:

private static List<File> retrieveAllNoTrashFiles(Drive service) throws IOException, InterruptedException {
    List<File> result = new ArrayList<File>();
    Files.List request = service.files().list().setQ("trashed = false").setMaxResults(1000);
    do {
        try {
            FileList files =executeRequest(service,request);
            result.addAll(files.getItems());
            request.setPageToken(files.getNextPageToken());
        } catch (IOException e) {       //here I sometimes get the read timeout
            System.out.println("An error occurred: " + e);
            request.setPageToken(null);
        }
    } while (request.getPageToken() != null
            && request.getPageToken().length() > 0);

    return result;
}

private static FileList executeRequest(Drive service,Files.List request) throws IOException, InterruptedException {
    Random randomGenerator = new Random();
    for (int n = 0; n < 5; ++n) {
        try {
            return(request.execute());
        } catch (GoogleJsonResponseException e) {
            if (e.getDetails().getCode() == 403
                    && (e.getDetails().getErrors().get(0).getReason().equals("rateLimitExceeded")
                    || e.getDetails().getErrors().get(0).getReason().equals("userRateLimitExceeded"))) {
                // Apply exponential backoff.
                Thread.sleep((1 << n) * 1000 + randomGenerator.nextInt(1001));
            } 
             //else {
                // Other error, re-throw.
               // throw e;
           // }
        }
    }catch(SocketTimeoutException e){
            Thread.sleep((1 << n) * 1000 + randomGenerator.nextInt(1001));
        }
    System.err.println("There has been an error, the request never succeeded.");
    return null;
}
4

3 回答 3

8

几天前我也有同样的经历。我的问题的答案在这里找到。https://code.google.com/p/google-api-java-client/wiki/FAQ。创建 Drive 的实例时,您可以调用 setHttpRequestInitializer 方法,将 HttpRequestInitializer 的新实例作为参数传递并实现 initialize 方法。在那里,您可以增加 ReadTimeout 和 ConnectionTimeout。

这是一个示例代码:

         Drive drive = new Drive.Builder(this.httpTransport, this.jsonFactory, this.credential).setHttpRequestInitializer(new HttpRequestInitializer() {

            @Override
            public void initialize(HttpRequest httpRequest) throws IOException {

                credential.initialize(httpRequest);
                httpRequest.setConnectTimeout(300 * 60000);  // 300 minutes connect timeout
                httpRequest.setReadTimeout(300 * 60000);  // 300 minutes read timeout

            }
        }).setApplicationName("My Application").build();
于 2014-05-18T00:05:57.783 回答
3

指数退避只是一种让您有更多机会重试的方法,希望下次会更好。但这并没有解决问题的根源。

我注意到您将最大结果设置为 1000。考虑到读取超时通常是由于服务器端处理时间过长造成的,我建议您将此数字减少到 500 或 200。

当我使用最大结果计数 1000 获取更改时遇到了同样的问题。当我将大小更改为 200 或 500 时,它运行顺利。

因为可接受的最大数量与服务器情况有关,并且是动态变化的,所以您还可以设计一个指数退避策略来自动更新最大结果计数。例如,从1000开始,如果遇到错误则更改为500,如果仍然存在错误则更改为200。如果一段时间没有错误,则再次增加到500。

希望这会有所帮助~

于 2013-12-27T17:24:37.480 回答
1

您的指数退避仅在您捕获 GoogleJsonException 时触发,而您在超时时不会收到该异常。您也可以在指数退避中捕获 SocketTimeoutException

于 2012-10-23T09:53:33.283 回答