2016-05-11 11 views
0

Ich verwende ein RESTful Framework (Flask-Restless 0.17.0 mit Flask-SQLAlchemy) als Backend. Und AngularJS als Frontend.Wie mit optimistischer Parallelität für REST-Ressourcen umgehen?

Ich weiß, dass man mit Nebenläufigkeit umgehen kann, indem man beispielsweise eine Versionsspalte (oder einen Zeitstempel oder eine Prüfsumme der Daten) für eine einzelne Tabelle verwendet.

So wie ich es jetzt Handhabung bin, ist wie folgt:

Alle SQLAlchemy-Modelle von CommonColumns erben:

class CommonColumns(db.Model): 
    __abstract__ = True 
    id = db.Column(db.Integer, primary_key=True)  
    aangemaakt = db.Column(db.DateTime) 
    gewijzigd = db.Column(db.DateTime) 
    etag = db.Column(db.String(40)) 

def commoncolumns_on_before_insert(mapper, connection, target): 
    """ Set time created and generate ETag on before_insert event. """ 
    # Set time created. 
    target.aangemaakt = datetime.now() 
    # Generate ETag based on SHA1-hash of time created. 
    target.etag = hashlib.sha1(str(target.aangemaakt)).hexdigest() 

def commoncolumns_on_before_update(mapper, connection, target): 
    """ Set time updated and generate ETag on before_update event. """ 
    # Set time updated. 
    target.gewijzigd = datetime.now() 
    # Generate ETag based on SHA1-hash of time updated. 
    target.etag = hashlib.sha1(str(target.gewijzigd)).hexdigest() 

event.listen(CommonColumns, 'before_insert', commoncolumns_on_before_insert, propagate = True) 
event.listen(CommonColumns, 'before_update', commoncolumns_on_before_update, propagate = True) 

Nach jeder Anfrage einen Code für die ETAG-Spalte sieht und einen Header erstellt für sie:

@app.after_request 
def add_etag_header(response): 
    """ Add etag-header contained in 'etag'-field inside returned JSON-object. 
    If no JSON returned, it wil silently ignore the exception and return the 
    response it would have returned anyway. 
    """ 
    try: 
     # Parse JSON. 
     jsonObject = json.loads(response.get_data()) 
     # Get etag field (if one) 
     etag = jsonObject.get('etag', None) 
     if etag != None: 
      # Return ETag as a header (for client, e.g. Restangular). 
      response.headers['ETag'] = etag 
    except Exception: 
     # Some unexpected exception occurred. Ignore for now. 
     pass 
    return response  

dann für jede API-Ressource verwende ich einen Prä-Prozessor, der diese Funktion aufruft:

def abort_on_etag_collision(model, instance_id): 
    """ Abort PUT/DELETE-operation for model (with ID=instance_id) when there is a 'mid-air-collision' 
    (when client-side and server-side ETags do not match). """ 
    # Store client-side ETag for comparison. 
    hdr_ifmatch_etag = request.headers.get('If-Match', None) 
    # Get server-side ETag from model for comparison. 
    current_etag = db.session.query(model).get(instance_id).etag 
    if current_etag == hdr_ifmatch_etag: 
     # Current ETag matches client-specified ETag, so let request through 
     pass 
    else: 
     # Current ETag is different from client-specified ETag, so return a 412 Precondition Failed! 
     # Also called a 'mid-air-collision'... 
     raise ProcessingException(description='Precondition Failed', code=412) 

Ich denke die 'abort_on_etag_collision' Funktion ist auch anfällig für eine Race Condition?

Aber zweitens, was ist, wenn Sie mehrere verwandte Tabellen haben. Und Sie können auf diese Tabellen über eine übergeordnete Ressource zugreifen, aber auch über untergeordnete Ressourcen. Es fällt mir schwer, herauszufinden, was der beste oder flexibelste Weg ist, damit umzugehen.

Ich möchte die Versionierung von sqlalchemy verwenden: http://docs.sqlalchemy.org/en/rel_1_0/orm/versioning.html

Aber dann muss ich in der Lage sein, die SQL zu ändern, um eine WHERE-Check für die Version enthalten (n) mich als SQLAlchemy nicht mach das automatisch und ich sehe keine Möglichkeit dafür mit Flask-Restless.

Jede Hilfe wird geschätzt.

Antwort

0

ich die Antwort auf meine Frage hier: https://stackoverflow.com/a/14690307/694400

Zusammenfassung: Ich sollte nur eine Prüfsumme für diese verwenden (statt einen Zeitstempel zu verwenden).

+0

Hallo zusammen - wenn Sie feststellen, dass Sie die Antwort auf eine andere Frage in Stack Overflow gefunden haben, ist es oft am besten, Ihre ursprüngliche Frage als ein Duplikat von diesem zu schließen. Auf diese Weise dienen doppelte Fragen als Wegweiser zu einem zentralen Q/A, anstatt die Antworten über Fragen zu fragmentieren. – Serlite

+0

@Serlite Scheint logisch. Ich werde es versuchen! – Wieger