大数量的NDB实体更新失败

时间:2015-04-25 19:47:49

标签: python google-app-engine bigdata google-cloud-datastore app-engine-ndb

我的任务非常简单。迁移并向现有NDB实体(~100K实体)添加新字段(重复和复合属性)后,我需要为它设置默认值。

我首先尝试了这个代码:

q = dm.E.query(ancestor=dm.E.root_key)
for user in q.iter(batch_size=500):
     user.field1 = [dm.E2()]
     user.put()

但它失败了这样的错误:

2015-04-25 20:41:44.792 /**** 500 599830ms 0kb AppEngine-Google; (+http://code.google.com/appengine) module=default version=1-17-0
W 2015-04-25 20:32:46.675 suspended generator run_to_queue(query.py:938) raised Timeout(The datastore operation timed out, or the data was temporarily unavailable.)
W 2015-04-25 20:32:46.676 suspended generator helper(context.py:876) raised Timeout(The datastore operation timed out, or the data was temporarily unavailable.)
E 2015-04-25 20:41:44.475 Traceback (most recent call last): File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/runtime/wsgi.py", line 267, in

任务在单独的任务队列上运行,因此它至少需要10分钟才能执行,但似乎还不够。奇怪的是:来自NDB的警告。可能存在死锁,因为来自其他实例的相同实体的更新(由用户启动)但不确定。

无论如何,我想知道这种任务的最佳实践(和最简单)。我知道MapReduce,但目前我认为这样的任务过于复杂。

更新

此外,我尝试通过抓取数组中的所有实体来使用put_multi但GAE会在超过~600 MB内存(限制为500 MB)时立即停止实例。似乎没有足够的内存来存储所有实体(~100K)。

1 个答案:

答案 0 :(得分:1)

执行_migrate_users()后,它将处理50个用户,然后创建另一个任务来处理接下来的50个用户,依此类推。 您可以使用大于50的批量大小,具体取决于实体的大小。

def _migrate_users(curs=None):
  users, next_curs, more = User.query().fetch_page(50, start_cursor=curs)
  for user in users:
    user.field1 = 'bla bla'
  ndb.put_multi(users)
  if more:
    deferred.defer(_migrate_users, next_curs, _queue='default')