1

使用新的 Google Cloud Storage 库 (appengine-gcs-client) 在 AppEngine 上运行导出到 CSV 作业时遇到以下错误。我有大约 30mb 的数据需要每晚导出。有时,我需要重建整个表。今天,我不得不重建所有东西(总共约 800mb),而我实际上只推了约 300mb。我检查了日志,发现了这个异常:

/task/bigquery/ExportVisitListByDayTask java.lang.RuntimeException:非最终块上的意外响应代码 200:请求:PUT https://storage.googleapis.com/moose-sku-data/visit_day_1372392000000_1372898225040.csv?upload_id=AEnB2UrQ1cw0-Jbt7Kr -S4FD2fA3LkpYoUWrD3ZBkKdTjMq3ICGP4ajvDlo9V-PaKmdTym-zOKVrtVVTrFWp9np4Z7jrFbM-gQ x-goog-api-version:2 内容范围:字节 4718592-4980735/*

262144 字节的内容

响应:200,内容为 0 字节 ETag:“f87dbbaf3f7ac56c8b96088e4c1747f6” x-goog-generation:1372898591905000 x-goog-metageneration:1 x-goog-hash:crc32c=72jksw== x-goog-hash:md5=+H27rz98591905000变化:来源日期:2013 年 7 月 4 日星期四 00:43:17 GMT 服务器:HTTP 上传服务器 建于 2013 年 6 月 28 日 13:27:54 (1372451274) 内容长度:0 内容类型:text/html;charset=UTF-8 X-Google-Cache-Control: remote-fetch Via: HTTP/1.1 GWA

at com.google.appengine.tools.cloudstorage.oauth.OauthRawGcsService.put(OauthRawGcsService.java:254)
at com.google.appengine.tools.cloudstorage.oauth.OauthRawGcsService.continueObjectCreation(OauthRawGcsService.java:206)
at com.google.appengine.tools.cloudstorage.GcsOutputChannelImpl$2.run(GcsOutputChannelImpl.java:147)
at com.google.appengine.tools.cloudstorage.GcsOutputChannelImpl$2.run(GcsOutputChannelImpl.java:144)
at com.google.appengine.tools.cloudstorage.RetryHelper.doRetry(RetryHelper.java:78)
at com.google.appengine.tools.cloudstorage.RetryHelper.runWithRetries(RetryHelper.java:123)
at com.google.appengine.tools.cloudstorage.GcsOutputChannelImpl.writeOut(GcsOutputChannelImpl.java:144)
at com.google.appengine.tools.cloudstorage.GcsOutputChannelImpl.waitForOutstandingWrites(GcsOutputChannelImpl.java:186)
at com.moose.task.bigquery.ExportVisitListByDayTask.doPost(ExportVisitListByDayTask.java:196)

该任务非常简单,但我想知道我使用 waitForOutstandingWrites() 的方式或我为下一个任务运行序列化 outputChannel 的方式是否有问题。需要注意的一点是,每个任务都分为每日组,每个组都输出自己的个人文件。每日任务计划以 10 分钟的间隔同时运行,以推出所有 60 天。

在任务中,我创建了一个 PrintWriter,如下所示: OutputStream outputStream = Channels.newOutputStream( outputChannel ); PrintWriter printWriter = new PrintWriter( outputStream );

然后一次将数据写入 50 行并调用 waitForOutstandingWrites() 函数将所有内容推送到 GCS。当我达到打开文件限制(约 22 秒)时,我将 outputChannel 放入 Memcache,然后使用数据迭代器的光标重新安排任务。

 printWriter.print( outputString.toString() );
 printWriter.flush();
 outputChannel.waitForOutstandingWrites();

这似乎大部分时间都在工作,但我收到了这些错误,这些错误正在 GCS 上创建〜损坏和不完整的文件。这些电话中有什么明显的我做错了吗?每个应用程序一次只能向 GCS 开放一个渠道吗?还有其他问题吗?

感谢您可以提供的任何提示!

谢谢!

埃文

4

1 回答 1

1

200 响应表示文件已完成。如果这发生在不是 close 的 API 上,则库会抛出错误,因为这不是预期的。

这可能与您重新安排任务的方式有关。可能是当您重新安排任务时,任务队列由于某种原因重复了任务的交付。(这可能发生)如果没有检查来防止这种情况,可能有两个实例试图同时写入同一个文件。当一个人关闭文件时,另一个人会看到错误。最终结果是一个损坏的文件。

简单的解决方案是不重新安排任务。文件可以在 GCS 客户端打开多长时间没有时间限制。(与已弃用的 Files API 不同。)

于 2013-07-08T22:51:52.720 回答