5

バックアップを容易にするために、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 ストレージに保存できるようにする方法についての提案をいただければ幸いです。ありがとう!

4

3 に答える 3

3

IMOではfiles.finalize(write_path)、間隔を空けてファイナライズするとファイルが読み取り可能になり、再度書き込み可能に変更することはできません。

于 2012-04-18T11:23:34.610 に答える
1

私は同じ問題を抱えていました。データをフェッチして例外をキャッチするイテレータを作成することになりましたが、動作しますが、回避策です。

コードを書き直すと、次のようになります。

from google.appengine.ext import blobstore
from google.appengine.api import files

def iter_blobstore(blob, fetch_size=524288):
  start_index = 0
  end_index = fetch_size

  while True:
    read = blobstore.fetch_data(blob, start_index, end_index)

    if read == "":
      break

    start_index += fetch_size
    end_index += fetch_size

    yield read


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:
    for buf in iter_blobstore(df.blob):
      try:
        fp.write(buf)
      except files.FileNotOpenedError:
        pass
  files.finalize(write_path)
于 2012-10-06T15:48:42.253 に答える
-1

バックエンドは選択できるオプションですか? これはバックグラウンドで実行され、TaskQueue よりもはるかに強力です。

于 2011-11-23T21:52:13.630 に答える