Как сделать транзакцию операций удаления blobstore безопасной с помощью ndb?

Если мы запускаем транзакцию для удаления сложного объекта в appengine, и к объекту прикреплены некоторые ссылки на большие двоичные объекты, которые необходимо удалить, у нас возникает проблема. Если мы просто удалим большие двоичные объекты, транзакция может завершиться неудачно, но большие двоичные объекты исчезнут, потому что хранилище больших двоичных объектов работает независимо (это противоречит идее транзакций).

Теперь у нас есть этот классный новый NDB, у которого есть контекстный кеш без документированного API (?), Который мог бы решить проблему.

Инструментальный ящик:

  • ndb.get_context () (недокументировано в ссылке на функцию ndb)
  • ndb_context.call_on_commit (delete_blobs_call_on_commit)

    def delete_blobs_call_on_commit():
       ndb_context = ndb.get_context()
       blobstore.delete(ndb_context.list_of_blobkeys_to_delete)
       # OR: taskqueue.add(url+ndb_context.list_of_blobkeys_to_delete)
    

Задача: прикрепить blobkeys для удаления во время транзакции к объекту контекста и удалить их после транзакции.

Обновление: call_on_commit () не разрешает операции с базой данных (которые могут включать blobstore.delete, но не пробовали) и выдает ошибку BadRequestError: невозможно начать новую операцию в завершенной транзакции, поэтому единственное решение действительно может быть очередь задач.

Обновление: можно вызвать функцию с помощью декоратора @ ndb.non_transactional из функции, зарегистрированной с помощью call_on_commit (). Таким образом, можно попытаться удалить капли при успешной фиксации и надеяться, что у вас нет исключений, которые могут привести к потере.

Вопросы: как безопасно использовать контекстный кеш? Как вы решили проблему с удалением больших двоичных объектов?


person cat    schedule 16.07.2013    source источник
comment
Как это решит проблему? Удаление blobkey все еще может завершиться неудачно, и теперь у вас есть потерянные blobkeys. Рассмотрите возможность использования модели транзакций перехода вперед, которая отслеживает оба удаления и запускает ее в задаче. Затем задача может подтвердить, что она удалила все, а затем очистить себя. Если в какой-то момент он потерпит неудачу, подметальщик может бросить вперед и повторить попытку, пока все сущности не исчезнут. Просто предложение.   -  person Tim Hoffman    schedule 16.07.2013
comment
Я рассматривал возможность помещения всех удаленных BLOB-объектов в очередь задач и удаления задач в случае сбоя транзакции, но это неудобно. delete_blobs_call_on_commit () может по-прежнему использовать очередь задач вместо прямого удаления больших двоичных объектов, но я подумал, что наличие нескольких сирот вполне допустимо. Если у blobstore 99,9% успеха, все в порядке. В основном этот вопрос касается сбора данных наката.   -  person cat    schedule 16.07.2013
comment
Вы читали эту статью, она может дать вам некоторые идеи в блоге. notdot.net/2009/9/Distributed-Transactions-on-App-Engine   -  person Tim Hoffman    schedule 16.07.2013
comment
Его добавили в закладки, спасибо.   -  person cat    schedule 16.07.2013
comment
Если ваша функция безопасного удаления всех blob-объектов требует транзакции, ее можно вызвать из call_on_commit, если вы украсите ее: @ndb.transactional(xg=True, propagation=ndb.TransactionOptions.MANDATORY). По крайней мере, до сих пор этот подход работал в моих экспериментах.   -  person Marc    schedule 12.06.2014


Ответы (2)


BLOB-объекты AFAIK на самом деле представлены в хранилище данных, чтобы вы могли использовать их в транзакциях.

Чтобы безопасно использовать контекстный кеш, используйте обычные операции Model / Key get () и put () с этими флагами: use_memcache = False, use_datastore = False, use_cache = True. Вы также можете поместить эти флаги в определение вашей модели как переменные класса.

person Guido van Rossum    schedule 16.07.2013
comment
Но объекты BlobInfo не имеют предка, и я понимаю, что предка нет == нет транзакции. Основная проблема, которую необходимо решить, заключается в том, что при удалении большого двоичного объекта во время транзакции этот большой двоичный объект удаляется даже в случае сбоя транзакции. - person cat; 17.07.2013
comment
Могли бы вы использовать транзакции XP? В противном случае вам придется жить с (очень) небольшой вероятностью того, что у вас будет утечка ключей blob. - person Guido van Rossum; 19.07.2013
comment
К сожалению, нет, у меня более 5 блобов в группе (кросс-группа (предел Xg равен 5). - person cat; 19.07.2013
comment
В настоящее время я принимаю возможность утечки некоторых BLOB-объектов, но избегаю потери BLOB-объектов перед фиксацией транзакции любой ценой, только очередь задач может решить проблему утечки, поскольку она может повторить попытку. - person cat; 19.07.2013

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

  1. Отметить объект / предка как удаленный, поставить (важно убедиться, что никто не может больше его использовать)
  2. Удалить без транзакции из листьев к родителю
  3. Каждый раз, когда возникает ошибка, отмените
  4. Пользователь (видит удаленный элемент) или система (очередь задач) может повторить удаление позже.
  5. Удаление должно иметь возможность пропускать уже удаленные ссылки, чтобы быть идемпотентным.

Может ли кто-нибудь увидеть проблему в таком подходе?

person cat    schedule 20.07.2013