2016-05-11 4 views
0

Я использую RESTful framework (Flask-Restless 0.17.0 с Flask-SQLAlchemy) в качестве бэкэнд. И AngularJS как интерфейс.Как справиться с оптимистичным параллелизмом для ресурсов REST?

Я знаю, что можно обрабатывать параллелизм, используя, например, столбец версии (или временную метку или контрольную сумму данных) для одной таблицы.

Путь я сейчас обращения с ним, как это:

Все SQLAlchemy-модели наследуют от CommonColumns:

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) 

После каждого запроса некоторый код ищет Etag столбца и создает заголовок для этого:

@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  

Тогда для каждого API ресурса я использую препроцессор, который вызывает эту функцию:

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) 

Я полагаю, что функция 'abort_on_etag_collision' также уязвима для состояния гонки?

Но, во-вторых, что, если у вас есть несколько связанных таблиц. И вы можете получить доступ к этим таблицам через родительский ресурс, но также через дочерние ресурсы. Мне трудно понять, что является лучшим или самым гибким способом борьбы с этим.

Я хотел бы использовать функцию управления версиями в SQLAlchemy: http://docs.sqlalchemy.org/en/rel_1_0/orm/versioning.html

Но тогда я должен быть в состоянии изменить SQL включить WHERE-проверку версии (ы) себя как SQLAlchemy не сделайте это автоматически, и я не вижу возможности для этого использовать Flask-Restless.

Любая помощь приветствуется.

ответ

0

Я нашел ответ на мой вопрос здесь: https://stackoverflow.com/a/14690307/694400

Резюме: я должен просто использовать контрольную сумму для этого (вместо использования метки времени).

+0

Привет, когда вы понимаете, что нашли ответ по другому вопросу в переполнении стека, часто лучше всего закрыть свой исходный вопрос в качестве дубликата этого. Таким образом, дублирующие вопросы служат указателями на центральный Q/A, а не фрагментируют ответы на вопросы. – Serlite

+0

@Serlite Кажется логичным. Я попробую! – Wieger

Смежные вопросы