Найти - Пользователи
Полная версия: События в транзакциях
Начало » Python для экспертов » События в транзакциях
1 2
o7412369815963
В больших проектах иногда задействовано много разных компонентов, интересуют технологии поддержки “целостности”.
Например сохраняем документ в MongoDB и при этом нужно обновить зависимый документ, обновить sphinx/elastic, отправить письмо, вызвать АПИ и т.п.
При этом если произойдет проблема на середине процесса (ошибки или хост потухнет), нужно будет все откатить.

По хорошему обработчики должны “навешиваться”, т.е. подключаем плагин, а он добавляет обработчик при сохранении пользователя (например db.user.add_trigger(some_method) или т.п.)

Например есть такой список обработчиков на сохранении:
1) Сохранение документа в БД
2) Вызвать API1
3) Обновление записи в sphinx/elastic
4) Отправка Email
5) Сохранение под-документа в БД
6) Отправить событие через websocket
7) Вызвать API2

С Email обычно проблем нет - добавляется задача в очередь, откатывать нечего (ну или отправить отменяющее письмо, а лучше вызвать это в конце процесса).
Транзакционные базы решают только сохранение в БД, т.е. всего 2 пункта из 7, не достаточно, или если там отдельная “sql”.
А вот с sphinx и API уже интересней, sphinx нужно будет откатить (удалить/записать старые данные), для АПИ - вызвать отменяющий/дополнительный метод.

Пример с API - не то которое можно поставить в очередь, а которое влияет на (возможность) сохранение.

Кто как решает подобную задачу, какие есть методики?
Alen
Задача не решаема в принципе.

Mongo - не поддерживает транзакции, откатить никак, поддержка целостности то что называют “в конечном счете”.
Для целостности нужно использовать CP-системы, например Zookeeper.

Sphinx сам по себе подразумевает возможность ошибок в поиске, ибо отвязан от базы, полнотекстовый поиск “есть” в самой mongo (правда сильно медленней sphinx).

В общем простых решений нет.
doza_and
Ну а по технологии откатывания: обычно используем связный список обработчиков с рекурсивным спуском при обработке и откатом по try …except.
Alen
doza_and
Ну а по технологии откатывания: обычно используем связный список обработчиков с рекурсивным спуском при обработке и откатом по try …except.

Ну то есть внешний обработчик, который поддерживает целостность и возможность отката, но дает непредсказуемый результат в случае распада системы.

Может это карта как-то поможет.
bismigalis
нужны транзакции на уровне приложения и операции должны поддерживать возможность отката

в пирамиде есть такое искаропки, для других можно слепить на основе repoze аналогов

есть такой пакет https://pypi.python.org/pypi/transaction

в пирамиде есть такой мидлваре https://pypi.python.org/pypi/pyramid_tm
который оборачивает запрос, если небыло ексепшенов в конце вызывается transaction.commit()
(wsgi аналог https://pypi.python.org/pypi/repoze.tm)

https://pypi.python.org/pypi/zope.sqlalchemy
подключает sqlalchemy транзакции к общей транзакции

https://pypi.python.org/pypi/pyramid_mailer
делает отправку мыла transaction aware
(аналог https://pypi.python.org/pypi/repoze.sendmail)

вижу вот такое есть еще https://pypi.python.org/pypi/pyramid_transactional_celery

для остальных операций нужно написать соответсвующие менеджеры :)


P.S. в доках и в названии пакетов не обращать внимание на упоминание ZOPE, концепция взята оттуда, зависимости от зопы уже нет
o7412369815963
Alen
Задача не решаема в принципе.
поддержка целостности то что называют “в конечном счете”.
Да, имел ввиду Eventual consistency

Alen
полнотекстовый поиск “есть” в самой mongo (правда сильно медленней sphinx).
Мне кажется он не сколько медленный, сколько требовательный к ресурсам, на одном проекте сильно жрет оперативку.

doza_and
Ну а по технологии откатывания: обычно используем связный список обработчиков с рекурсивным спуском при обработке и откатом по try …except.
Интересный вариант, но тут 2 проблемы:
1)
Alen
дает непредсказуемый результат в случае распада системы.
2) Если например sphinx берет текущее значение из БД для обновления, то при откате, sphinx нужно вызывать в конце, хотя конкретно для сфинкса не обязательно, можно держать старое значение для отката. Можно ли так покрыт все случаи?
Alen
o7412369815963
Да, имел ввиду Eventual consistency

Ну тогда у вас для этого всё есть, необходимо хранить текущий статус операций в mongo ибо она как раз BASE-архитектуры (естественно реплицированной 3 узла минимум).

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

o7412369815963
Alen
необходимо хранить текущий статус операций в mongo
У меня в голове другой вариант, в момент “транзакции”, каждый шаг (sphinx/api…) вначале регистрирует свой rollback метод с приоритетом в документ транзакции, далее выполняет необходимые действия.
В итоге каждая транзакция может иметь свою цепочку rollback - зависит от логики.

Если выпал exception, то где-то сверху, где была создана транзакция ставится статус = “rollback”, - воркер подхватывает и отрабатывает зарегистрированные rollback методы в порядке приоритета.
Если транзакция висит долго (timeout), воркер сам переводит транзакцию в rollback.
Так же если система упала, то можно перед запуском все повисшие транзакции перевести в rollback.
Как то так…

Alen
естественно реплицированной 3 узла минимум
Эта рекомендация уже не так актуальна, т.к. журнал дает сопоставимую *sql'ям надежность в пределах одной ноды.
o7412369815963
Alen
Т.е. для каждой операции свой набор воркеров работающих независимо
Почему для каждой операции свои воркеры?
Мне кажется вариант, где все воркеры умеют выполнять любые операции, лучше. - просто “докидывать” один и тот же воркер на сервера если нужно больше производительности.
Alen
o7412369815963
Эта рекомендация уже не так актуальна, т.к. журнал дает сопоставимую *sql'ям надежность в пределах одной ноды.

Если хост в дауне, журнал не поможет.

o7412369815963
Почему для каждой операции свои воркеры?
Мне кажется вариант, где все воркеры умеют выполнять любые операции, лучше. - просто “докидывать” один и тот же воркер на сервера если нужно больше производительности.

Да, вы правы, имеет смысл если маршрут задач постоянен.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB