Ordani Sanchez
Ordani Sanchez

Reputation: 401

How do i get strongly consistency in GAE in Python enviroment

I got a website, most like a blog, and when I submit a post it immediately put it in the db and update the cache too. It looks like that when the cache try to update itself, the db is not updated, and I got a cache out of date, with I got a front page without the last post, I tried putting time.sleep(1), and then it worked but I want to know if that have to be with that I'm not using a parent for my entities, and if that is how may I do that?

def cachFront(update=False):
    key="top"
    entradas=memcache.get(key)
    if entradas is None or update:
        logging.error("DB QUERY")
        post= db.GqlQuery("select * from dbEntradas order by fecha_creacion desc limit 10")
        entradas=list(post)
        memcache.set(key, entradas)
    return entradas


class MainHandler(Handler):
    def get(self):
        entradas= cachFront()
        self.render("index.html", entradas=entradas)


class NewPostHandler(Handler):

    def renderizar(self, error="", titulo="", post=""):
        self.render("entradas.html", titulo=titulo, post=post, error=error)

    def get(self):
        self.render("entradas.html")

    def post(self):
        titulo= self.request.get("title")
        topic= self.request.get("topic")
        post= self.request.get("post")

        if titulo and post  and (topic!="Choose one.."):
            entrada= post_db.dbEntradas(title=titulo, post=post, topic=topic)
            entrada.put()
            time.sleep(1)// if i commet this line when i redirect i do not get a cache update intead i got the old page
            cachFront(True)
            self.redirect('/')

Upvotes: 0

Views: 66

Answers (2)

Josh J
Josh J

Reputation: 6893

Notice the change I made to cachFront and to the call to cachFront inside of your post method to manually prepend your entry in the case where eventual consistency hasn't replicated.

def cachFront(update=False, prepend=None):
    key="top"
    entradas=memcache.get(key)
    if entradas is None or update:
        logging.error("DB QUERY")
        post= db.GqlQuery("select * from dbEntradas order by fecha_creacion desc limit 10")
        entradas=list(post)
        # manually prepend item to cache if it isn't available yet because
        # of eventual consistency
        if prepend and (not entradas or not entradas[0].key == prepend.key):
            entradas.insert(0, prepend)
            entradas = entradas[0:10]
        memcache.set(key, entradas)
    return entradas


class MainHandler(Handler):
    def get(self):
        entradas= cachFront()
        self.render("index.html", entradas=entradas)


class NewPostHandler(Handler):

    def renderizar(self, error="", titulo="", post=""):
        self.render("entradas.html", titulo=titulo, post=post, error=error)

    def get(self):
        self.render("entradas.html")

    def post(self):
        titulo= self.request.get("title")
        topic= self.request.get("topic")
        post= self.request.get("post")

        if titulo and post  and (topic!="Choose one.."):
            entrada= post_db.dbEntradas(title=titulo, post=post, topic=topic)
            entrada.put()
            cachFront(update=True, prepend=entrada)
            self.redirect('/')

Upvotes: 1

Tim D
Tim D

Reputation: 205

To answer your question specifically, yes, you could use parent / ancestor entities to solve your problem. If you expect to never make a write to your dbEntradas entities more than around 1/second, then this can be a fine solution.

Using parent entities tells datastore to keep all of those entities that share an ancestor relationship on the same server (basically to not replicate the data). Thus, you won't have to use time.sleep() to allow your entity to be written, as the following GQL call will be guaranteed to see the data from your earlier put.

You will need to choose one entity that will be the parent of all entities, and use that every time you make a new entrada:

post_db.dbEntradas(title=titulo, post=post, topic=topic, parent=post_parent)

In this case, I would suggest just making your first post the default parent, and grab its key. So your code would become:

def post(self):
    titulo= self.request.get("title")
    topic= self.request.get("topic")
    post= self.request.get("post")

    if titulo and post  and (topic!="Choose one.."):
        parent_entrada = post_db.dbEntradas.query(post_db.dbEntradas.id == [[first_post_id_here]]).get()

        entrada= post_db.dbEntradas(title=titulo, post=post, topic=topic, parent = parent_entrada)
        entrada.put()
        cachFront(True)
        self.redirect('/')

Upvotes: 0

Related Questions