In Google App Engine, how can I work with eventual consistency in handling form submissions?

时光总嘲笑我的痴心妄想 提交于 2019-12-19 08:41:10

问题


I've noticed that, with eventual consistency, the common form-processing workflow that I am used to (submit -> create/update record -> redirect -> reload) doesn't work. Upon redirect, the new record (probably) won't be available for display. How should I handle forms so that updates are displayed upon reload?

I could try to use strong consistency, but as the App Engine documentation notes, updates are limited to one update per second.

So how can I process a form providing immediate user feedback with eventual consistency?


回答1:


Try to restructure your code so that you are getting by key (which always gives you the most recent data) instead of doing a query. I realize this isn't always possible, but I'll give you a recent example of something that worked for me.

I have a user dashboard where a user can create and delete "items". My entities looked like this:

class User(ndb.Model)
    ...

class Item(ndb.Model)
    user = ndb.KeyProperty(User, required=True)

In the past, I would do a query like this when responding to a GET request for the user dashboard.

items = Item.query(user=user.key)

This was a bad experience because a user would delete an item and after the POST/redirect/GET the just deleted item would again appear in the dashboard because of eventual consistency.

To fix this, I changed my User entity to have a list of Items like this:

class User(ndb.Model)
    items = ndb.KeyProperty(repeated=True)
    ...

Now, when I show the dashboard, I do this:

items = ndb.get_multi(user.items)

Since I am now getting by key, the data is always up to date.

This works for me because a user won't have that many items. If a user could have thousands of items, however, this approach wouldn't work because of the entity size limit.




回答2:


You probably still can use strong consistency, as long as you design your entity groups properly. Reading closely on the doc linked, the restriction is actually only one update per second per entity group.

This is because Google's underlying masterless consistency protocol ("Paxos") guarantees strong consistency only when working within an entity group (being defined as an entire group of keys, under a root key and including that root key, where the eventual parent of all non-root keys is that root key - see Transactions and entity groups for more).

Quoth the manual:

As mentioned above, an entity group is a set of entities connected through ancestry to a common root element. The organization of data into entity groups can limit what transactions can be performed:

... [ details about transactions ] ...

  • There is a write throughput limit of about one transaction per second within a single entity group. This limitation exists because Datastore performs masterless, synchronous replication of each entity group over a wide geographic area to provide high reliability and fault tolerance.

So, if you architect your Datastore keys to use, say, the logged-in-user's ID or email address as a parent key, reading the resulting key on the other end can be guaranteed strongly consistent by specifying that key as an ancestor.

It's also worth noting that an entity doesn't technically have to exist at that parent key - you just need a key to start the root of your entity group so that you can apply your consistency guarantee.

If you can architect that way, you can both guarantee consistency and apply writes at one-per-second-per-user, or whatever you scope your keys to.

For more info, see "Structuring for Strong Consistency".



来源:https://stackoverflow.com/questions/34818695/in-google-app-engine-how-can-i-work-with-eventual-consistency-in-handling-form

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!