Google App Engine数据存储查询返回陈旧数据

问题描述:

我有一个基于GAE的项目,使用dbDatastore。在我的项目中,我每15分钟运行一次作业,并更新Datastore中的数据。然后我有一个端点查询Datastore并显示结果。但是,我得到的结果是陈旧的,而不是更新的结果。看来GAE没有打到Datastore并从缓存中返回数据,但我不确定。这里是我的代码:Google App Engine数据存储查询返回陈旧数据

class MainHandler(webapp2.RequestHandler): 

    def get(self): 
     query = Contests.all() 
     contests_data = query.fetch(1) # fetch the data from datastore 
     self.response.write(contests_data[0].data) 

class DataBaseHandler(webapp2.RequestHandler): 

    # the job that runs every 15 minutes 
    def get(self): 
     contests_data = get_all_contests() # get the new data 
     query = Contests.all() 
     contests = query.fetch(1) 
     contests[1].data = contests_data # update the data 
     db.put(contests[0]) 
     self.response.write(json.dumps({"message":"updated"})) 

这里是我的模型:

class Contests(db.Model): 
    """Models Contests""" 
    data = db.TextProperty(default="{}") 
    created = db.DateTimeProperty(auto_now_add=True) 
    modified = db.DateTimeProperty(auto_now=True) 

我尝试使用memcache.flush_all()但即使是不解决问题的清除缓存。为什么GAE不返回更新的数据?我该如何解决这个问题?

编辑:我改变了查询祖先查询,但数据仍旧陈旧(和它是天)。

main.py

class MainHandler(webapp2.RequestHandler): 

     def get(self): 
      contest_list = ContestList.get_or_insert('contest_list', name='ContestList') 
      query = Contests.all() 
      query.ancestor(contest_list) 
      contests = query.fetch(1) 
      self.response.write(contests[0].data) 

    class DataBaseHandler(webapp2.RequestHandler): 

     def get(self): 
      contests_data = get_all_contests() 
      contest_list = ContestList.get_or_insert('contest_list', name='ContestList') 
      query = Contests.all() 
      query.ancestor(contest_list) 
      contests = query.fetch(1) 
      contests[0].data = contests_data 
      contests[0].put() 
      self.response.write(json.dumps({"message":"updated"})) 

models.py

class ContestList(db.Model): 
    name = db.StringProperty() 

class Contests(db.Model): 
    """Models Contests""" 
    data = db.TextProperty(default="{}") 
    created = db.DateTimeProperty(auto_now_add=True) 
    modified = db.DateTimeProperty(auto_now=True) 

我甚至尝试使用key获取数据:

class MainHandler(webapp2.RequestHandler): 

    def get(self): 
     q = ndb.Key('Contests', 'contest_data').get() 
     if q: 
      self.response.write(q.data) 
     else: 
      self.response.write("error") 

class DataBaseHandler(webapp2.RequestHandler): 

    def get(self): 
     Contests(key=ndb.Key('Contests', "contest_data"), data=get_all_contests()).put() 
     self.response.write(json.dumps({"message":"updated"})) 

什么不打GAE数据存储?我在这里错过了什么?

+1

Patrice的回答是正确的 - 旧的crufty'db'并不会透明地为你缓存,你需要新的伟大的'ndb'(当然,通过使用自定义上下文来控制),所以遇到的问题'db'不能由于缓存,必须与最终一致性相关, – 2015-02-07 19:31:49

+0

最终一致性需要1-2秒才能解决。如果您的数据超出了“陈旧”,那么您的代码中就有一个问题。 – 2015-02-07 19:35:34

+1

@AndreiVolgin,第二个或通常更少是* typical *,但没有保证最坏情况延迟的上限。现代子系统(如ndb)的用户几乎从未观察到,因为memcache **具有强烈的一致性(虽然是volatile) - 但是对于旧的crufty db来说更加突出,反正“几乎没有”与“never”一样: - )... – 2015-02-07 19:47:31

数据存储区最终只对查询一致。在数据复制过程中,确实存在一种可能性,那就是您打到“陈旧”的数据。

为了确保您在查询中强制保持一致性,您需要使用祖先查询或get by键。

了解更多关于这个here

例:祖先查询

documentation)为了做到这一点,你显然需要改变你的结构位。我不知道什么可能是模型“竞赛”的祖先,但我们假设他们都属于“主祖先”实体。

当您创建实体,你需要有一个类似于:

query = Contests.all() 
query.ancestor(mainAncestor) 
contests = query.fetch(1) 

这将迫使强:

newContest = Contest(parent=mainAncestor) 

然后,当您检索,您在代码中添加此数据的一致性。您显然需要创建该“mainAncestor”,然后它会导致您需要确保解决的其他警告(例如,您只能每秒钟向实体组(在同一祖先下编组的实体)写入一次),例如)。

+2

很好的答案,但要使它很棒我有两个建议:(一)你也可以直接链接到https://cloud.google.com/developers/articles/balancing-strong-and-eventual-consistency-with-google-云数据存储/(不需要通过那个以Java为核心的SO Q :-)来发送OP,而且(B)理想地提供了一个简单的Python例子,说明如何在OP的用例中人为地使用祖先查询...我upvoted无论如何,但建议你丰富答案!) – 2015-02-07 19:43:34

+0

公平点。对于A)来说,这实际上是我打算使用的链接。我应该仔细检查。我会纠正这一点,并简单地添加B :)。感谢您的建议 – Patrice 2015-02-07 19:46:54

+0

@Patrice @AlexMartelli非常感谢您的帮助!但即使在添加祖先查询并试图通过'key'获取数据之后,它也不起作用。我已经编辑了更多细节的问题。 – 2015-02-09 07:11:29