Frage

Der App Engine-Datenspeicher, hat natürlich Ausfallzeiten . Ich würde jedoch gerne hätte ein „fail-safe“ setzen was angesichts der Datenspeicher Fehler robuster ist (siehe Motivation unten). Es scheint, wie die Task-Warteschlange ein offensichtliches Stelle schreibt zu verschieben, wenn der Datenspeicher nicht verfügbar ist. Ich weiß nicht, von anderen Lösungen aber (anders als die Daten an einen Drittanbieter über urlfetch Versand aus).

Motivation : Ich ein Unternehmen haben, die wirklich in den Datenspeicher gesetzt werden muss - einfach eine Fehlermeldung an den Benutzer zeigt nicht tun. Zum Beispiel, vielleicht hat einige Nebenwirkung erfolgt, die nicht leicht rückgängig gemacht werden (vielleicht mit einem Drittanbieter-Website einige Interaktion) sein kann.

Ich habe kommen mit einem einfachen Wrapper, der (glaube ich) ein hinreichend sicheren „fail-safe“ put (siehe unten). Siehst du irgendwelche Probleme mit diesem, oder haben eine Idee für eine robustere Implementierung? (Anmerkung:. Dank Vorschläge in den Antworten von Nick Johnson und Saxon Druce geschrieben, dieser Beitrag zu dem Code wurde mit einigen Verbesserungen bearbeitet)

import logging
from google.appengine.api.labs.taskqueue import taskqueue
from google.appengine.datastore import entity_pb
from google.appengine.ext import db
from google.appengine.runtime.apiproxy_errors import CapabilityDisabledError

def put_failsafe(e, db_put_deadline=20, retry_countdown=60, queue_name='default'):
    """Tries to e.put().  On success, 1 is returned.  If this raises a db.Error
    or CapabilityDisabledError, then a task will be enqueued to try to put the
    entity (the task will execute after retry_countdown seconds) and 2 will be
    returned.  If the task cannot be enqueued, then 0 will be returned.  Thus a
    falsey value is only returned on complete failure.

    Note that since the taskqueue payloads are limited to 10kB, if the protobuf
    representing e is larger than 10kB then the put will be unable to be
    deferred to the taskqueue.

    If a put is deferred to the taskqueue, then it won't necessarily be
    completed as soon as the datastore is back up.  Thus it is possible that
    e.put() will occur *after* other, later puts when 1 is returned.

    Ensure e's model is imported in the code which defines the task which tries
    to re-put e (so that e can be deserialized).
    """
    try:
        e.put(rpc=db.create_rpc(deadline=db_put_deadline))
        return 1
    except (db.Error, CapabilityDisabledError), ex1:
        try:
            taskqueue.add(queue_name=queue_name,
                          countdown=retry_countdown,
                          url='/task/retry_put',
                          payload=db.model_to_protobuf(e).Encode())
            logging.info('failed to put to db now, but deferred put to the taskqueue e=%s ex=%s' % (e, ex1))
            return 2
        except (taskqueue.Error, CapabilityDisabledError), ex2:
            return 0

Request-Handler für die Aufgabe:

from google.appengine.ext import db, webapp

# IMPORTANT: This task deserializes entity protobufs.  To ensure that this is
#            successful, you must import any db.Model that may need to be
#            deserialized here (otherwise this task may raise a KindError).

class RetryPut(webapp.RequestHandler):
    def post(self):
        e = db.model_from_protobuf(entity_pb.EntityProto(self.request.body))
        e.put() # failure will raise an exception => the task to be retried

I nicht erwarten, dass dies zu verwenden, um alle gesetzt - die meiste Zeit, zeigt eine Fehlermeldung ist nur in Ordnung. Es ist verlockend es für jeden in Gebrauch genommen, aber ich denke, manchmal könnte es für den Benutzer verwirrend sein, wenn ich ihnen sagen, dass ihre Änderungen später erscheinen wird (und sie auch weiterhin die alten Daten zeigen, bis der Datenspeicher-up ist zurück und die latenten puts execute).

War es hilfreich?

Lösung

Ihr Ansatz ist vernünftig, hat aber einige Einschränkungen:

  • Standardmäßig wird eine Put-Operation wiederholen, bis es von Zeit abläuft. Da Sie eine Backup-Strategie haben, können Sie früher aufgeben wollen -. In diesem Fall sollten Sie einen RPC-Parameter der Put-Methodenaufruf liefern, eine benutzerdefinierte Frist Angabe
  • Es gibt keine Notwendigkeit, einen expliziten Countdown zu setzen -. Die Task-Warteschlange erneut versuchen wird der Betrieb für Sie bei steigenden Abständen andernfalls
  • Sie haben nicht zu verwenden Gurke müssen - Protocol Buffers eine natürliche String-Codierung haben, die viel effizienter ist. Siehe diesen Beitrag für eine Demonstration, wie es zu benutzen.
  • Wie Saxon weist darauf hin, Task-Queue-Nutzlasten bis 10 Kilobyte begrenzt sind, so dass Sie Probleme mit großen Einheiten haben.
  • Am wichtigsten ist, ändert sich die Datenspeicherkonsistenzmodell von ‚stark konsistent‘ zu ‚schließlich im Einklang‘. Das heißt, der Put, dass Sie die Task-Warteschlange eingereiht könnte jederzeit in der Zukunft angewendet werden, alle Änderungen überschreiben, die in der Zwischenzeit vorgenommen wurden. Eine beliebige Anzahl von Rennbedingungen möglich sind, im Wesentlichen Rendering Transaktionen nutzlos, wenn es ausstehende Puts auf der Task-Warteschlange.

Andere Tipps

Ein potentielles Problem ist, dass Aufgaben beschränken sich auf 10kb Daten , so das wird nicht funktionieren, wenn Sie ein Unternehmen, das als das größer ist einmal gebeizt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top