1

j'ai eu cette erreur:TransactionFailedError sur GAE quand aucune transaction

TransactionFailedError: too much contention on these datastore entities. please try again. 

Même si je ne fais pas de transactions. La ligne de mon code qui provoque l'erreur est

ndb.put_multi(entity_list) # entity_list is a list of 100 entities 

Cette erreur ne se produit pas souvent il est donc pas une grosse affaire, mais je suis curieux de savoir pourquoi je reçois cette erreur. Des idées?

Voici la plupart des retraçage:

Traceback (most recent call last): 
    ... 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/deferred/deferred.py", line 318, in post 
    self.run_from_request() 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/deferred/deferred.py", line 313, in run_from_request 
    run(self.request.body) 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/deferred/deferred.py", line 155, in run 
    return func(*args, **kwds) 
    File "/base/data/home/apps/s~opavote/2017-09-15.404125237783169549/tasks.py", line 70, in start_election 
    models.Voter.create(e.eid, chunk) 
    File "/base/data/home/apps/s~opavote/2017-09-15.404125237783169549/models.py", line 2426, in create 
    ndb.put_multi(voters + vbs) 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/model.py", line 3958, in put_multi 
    for future in put_multi_async(entities, **ctx_options)] 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 383, in get_result 
    self.check_success() 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 427, in _help_tasklet_along 
    value = gen.throw(exc.__class__, exc, tb) 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/context.py", line 824, in put 
    key = yield self._put_batcher.add(entity, options) 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 427, in _help_tasklet_along 
    value = gen.throw(exc.__class__, exc, tb) 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/context.py", line 358, in _put_tasklet 
    keys = yield self._conn.async_put(options, datastore_entities) 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 513, in _on_rpc_completion 
    result = rpc.get_result() 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/datastore/datastore_rpc.py", line 928, in get_result 
    result = rpc.get_result() 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/api/apiproxy_stub_map.py", line 613, in get_result 
    return self.__get_result_hook(self) 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/datastore/datastore_rpc.py", line 1893, in __put_hook 
    self.check_rpc_success(rpc) 
    File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/datastore/datastore_rpc.py", line 1385, in check_rpc_success 
    raise _ToDatastoreError(err) 
TransactionFailedError: too much contention on these datastore entities. please try again. 

Répondre

3

Notez que l'erreur est effectivement reçue du datastore lui-même, dans la réponse du RPC: self.check_rpc_success(rpc). Ce qui me fait penser que du côté de la banque de données, pour assurer la cohérence et la fiabilité des opérations entre les parties redondantes de l'infra, chaque opération d'écriture utilise en fait les mêmes mécanismes que pour les opérations transactionnelles. La différence serait que ceux-ci ont également des vérifications transactionnelles du côté client, avant/après l'échange RPC et peut-être des déclencheurs de début/fin de transaction RPC explicites pour le magasin de données.

De Life of a Datastore Write, une citation suggérant que certains mécanismes communs sont utilisés indépendamment des opérations étant transactionnel ou non (Souligné par l'auteur):

If the commit phase has succeeded but the apply phase failed, the datastore will roll forward to apply the changes to indexes under two circumstances:

  1. The next time you execute a read or write or start a transaction on this entity group, the datastore will first roll forward and fully apply this committed but unapplied write, based on the data in the log.

Et l'une des raisons possibles des échecs serait tout simplement trop des accès parallèles aux mêmes entités, même si elles sont en lecture seule. Voir Contention problems in Google App Engine, bien que dans ce cas, ils sont pour les transactions du côté client.

Notez que ceci est juste une théorie;)

+0

La première page que vous avez liée indique qu'il existe "un taux d'échec attendu sur les écritures, car les tablettes BigTable sont parfois indisponibles". Je soupçonne que c'est ce qui s'est passé ici et que l'échec faisait partie d'une transaction en ce sens. –

2

Il pourrait être utile de re-revoir transactions and entity groups, en notant les diverses définitions et des limites. Putting "Chaque tentative de création, de mise à jour ou de suppression d'une entité a lieu dans le contexte d'une transaction" et "Il existe une limite de débit en écriture d'environ une transaction par seconde au sein d'un même groupe d'entités". parle de ce que vous voyez, en particulier si entity_list contient des entités qui appartiennent au même groupe d'entités.

+0

Les entités mises ici sont créées et je n'utilise aucun groupe d'entités. Il semble qu'une transaction est utilisée sous le capot pour créer les entités. Il me semble étrange que vous puissiez avoir des conflits lors de la création d'une entité. –

+2

Fournissez-vous vos propres noms de clés ou laissez-vous les attribuer automatiquement? Le premier peut causer des problèmes de contention si les clés sont vraiment proches les unes des autres (par exemple, séquentielles). Les ID attribués automatiquement l'évitent. –

+0

J'ai des noms de clés personnalisés qui sont créés en concaténant un ID d'une entité différente avec une adresse e-mail d'un utilisateur, quelque chose comme [email protected] Dans certains cas, les adresses électroniques proviendront toutes du même domaine, de sorte que la seule différence entre les clés se situera entre le "_" et le "@". Est-ce que cela rendrait les clés suffisamment rapprochées pour potentiellement causer des problèmes de contention? –