バックアップを容易にするために、Google App Engine の Blobstore から Google Cloud Storage に大きなファイルを保存しようとしています。
小さなファイル (<10 mb) では問題なく動作しますが、大きなファイルでは不安定になり、GAE がスローして FileNotOpenedError が発生します。
私のコード:
PATH = '/gs/backupbucket/'
for df in DocumentFile.all():
fn = df.blob.filename
br = blobstore.BlobReader(df.blob)
write_path = files.gs.create(self.PATH+fn.encode('utf-8'), mime_type='application/zip',acl='project-private')
with files.open(write_path, 'a') as fp:
while True:
buf = br.read(100000)
if buf=="": break
fp.write(buf)
files.finalize(write_path)
(実行時間の超過を避けるために taskeque で実行されます)。
FileNotOpenedError をスローします。
トレースバック (最新の呼び出しが最後): ファイル "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py"、1511 行目、__call__ 内 rv = self.handle_exception(リクエスト、レスポンス、e) ファイル "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py"、1505 行目、__call__ 内 rv = self.router.dispatch(リクエスト、レスポンス) ファイル「/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py」、行 1253、default_dispatcher 内 return route.handler_adapter(リクエスト、レスポンス) ファイル "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py"、1077 行目、__call__ 内 戻ります handler.dispatch() ファイル「/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py」、行 547、ディスパッチ return self.handle_exception(e, self.app.debug) ファイル「/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py」、行 545、ディスパッチ return メソッド (*args, **kwargs) ファイル「/base/data/home/apps/s~simplerepository/1.354754771592783168/processFiles.py」、249行目、ポスト fp.write(buf) ファイル「/base/python27_runtime/python27_lib/versions/1/google/appengine/api/files/file.py」、281 行目、__exit__ 内 self.close() ファイル「/base/python27_runtime/python27_lib/versions/1/google/appengine/api/files/file.py」の 275 行目付近 self._make_rpc_call_with_retry('クローズ', リクエスト, レスポンス) ファイル "/base/python27_runtime/python27_lib/versions/1/google/appengine/api/files/file.py"、388 行目、_make_rpc_call_with_retry 内 _make_call(メソッド、リクエスト、レスポンス) ファイル "/base/python27_runtime/python27_lib/versions/1/google/appengine/api/files/file.py"、236 行目、_make_call 内 _raise_app_error(e) ファイル「/base/python27_runtime/python27_lib/versions/1/google/appengine/api/files/file.py」、179 行目、_raise_app_error 内 FileNotOpenedError() を上げる
さらに調査したところ、 GAE Issue 5371へのコメントによると、Files API は 30 秒ごとにファイルを閉じます。私はこれが他のどこにも文書化されているのを見たことがありません。
間隔を置いてファイルを閉じたり開いたりすることでこれを回避しようとしましたが、今は WrongOpenModeError が発生します。以下のコードは、この記事の最初のバージョンから編集したものです。ファイルを閉じてから開くまでの間に 0.5 秒の一時停止を追加しました。WrongOpenModeError をスローするようになりました。
私のコード(更新):
PATH = '/gs/backupbucket/'
for df in DocumentFile.all():
fn = df.blob.filename
br = blobstore.BlobReader(df.blob)
write_path = files.gs.create(self.PATH+fn.encode('utf-8'), mime_type='application/zip',acl='project-private')
fp = files.open(write_path, 'a')
c = 0
while True:
if (c == 5):
c = 0
fp.close()
files.finalize(write_path)
time.sleep(0.5)
fp = files.open(write_path, 'a')
c = c + 1
buf = br.read(100000)
if buf=="": break
fp.write(buf)
files.finalize(write_path)
スタックトレース:
トレースバック (最新の呼び出しが最後): ファイル "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py"、1511 行目、__call__ 内 rv = self.handle_exception(リクエスト、レスポンス、e) ファイル "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py"、1505 行目、__call__ 内 rv = self.router.dispatch(リクエスト、レスポンス) ファイル「/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py」、行 1253、default_dispatcher 内 return route.handler_adapter(リクエスト、レスポンス) ファイル "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py"、1077 行目、__call__ 内 戻ります handler.dispatch() ファイル「/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py」、行 547、ディスパッチ return self.handle_exception(e, self.app.debug) ファイル「/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py」、行 545、ディスパッチ return メソッド (*args, **kwargs) ファイル "/base/data/home/apps/s~simplerepository/1.354894420907462278/processFiles.py"、267 行目、get fp.write(buf) ファイル「/base/python27_runtime/python27_lib/versions/1/google/appengine/api/files/file.py」、310 行目、書き込み self._make_rpc_call_with_retry('Append', リクエスト, レスポンス) ファイル "/base/python27_runtime/python27_lib/versions/1/google/appengine/api/files/file.py"、388 行目、_make_rpc_call_with_retry 内 _make_call(メソッド、リクエスト、レスポンス) ファイル "/base/python27_runtime/python27_lib/versions/1/google/appengine/api/files/file.py"、236 行目、_make_call 内 _raise_app_error(e) ファイル「/base/python27_runtime/python27_lib/versions/1/google/appengine/api/files/file.py」、188 行目、_raise_app_error 内 WrongOpenModeError() を上げる
WrongOpenModeError に関する情報を見つけようとしましたが、言及されている唯一の場所は appengine.api.files.file.py 自体です。
これを回避し、大きなファイルも Google Cloud ストレージに保存できるようにする方法についての提案をいただければ幸いです。ありがとう!