Re[11]: Блокировки в бизнес-слое
От: · Великобритания  
Дата: 28.09.17 07:53
Оценка:
Здравствуйте, Poul_Ko, Вы писали:

P_K>Здравствуйте, ·, Вы писали:


P_K>·>Или я тебя совсем не понимаю, или ты не ту цель пытаешься достигнуть. Цель не добиться "одновременности" (что это вообще значит?!), а создать согласованное состояние, установить причинность событий.

P_K>Не пытаюсь добиться одновременности, а наоборот, пытаюсь от неё избавиться, так как она порождает проблемы.
P_K>Способов избавления пока вижу два — либо всегда всё жёстко делать последовательно, либо на каких-то блокировках не давать делать одновременно некоторые операции.

P_K>>>·> Любые последующие изменения цены "официально" считаются, что произошли после, а значит не должны влиять на заказ.

P_K>>>Категорически нет. Смотрите выше — изменение цены после приводит к пересчёту неподтверждённых заказов!
P_K>·>1. Создать неподтверждённый заказ товара по ценам из справочника.
P_K>·>2. Показать заказ клиенту, клиент шлёт команду "подтвердить".
P_K>·>3. Сверяем цены в заказе с ценами в справочнике
P_K>·>4.1 Цены равны — ставим статус "подтверждён"
P_K>·>4.2 Цены не равны — возвратить клиенту ошибку, пересчитать заказ с учётом новых цен и goto 2.
P_K>·>Т.е. по сути у тебя тут распределённая система из двух компонент — клиент и сервер — они и должны согласовываться.
P_K>Нет, это не соответствует действительности.
P_K>У клиента одно действие — создать новый неподтверждённый заказ. Этот заказ создаётся и болтается в системе пока его не подтвердят или не отменят. И пока он болтается неподтверждённый цена в нём всегда должна строго соответствовать цене из справочника.
Это означает, что тебе нужно задать явную временнУю зависимость заказа от цены. Помимо того, что я упомянул уже, вариант — заблокировать продукт перед созданием ордера:
SELECT Price FROM Products WHERE Id = 1 FOR UPDATE;
...Cost = Price * Qty...
INSERT INTO Orders(...) VALUES(..., Cost, ...);

Но тут надо очень осторожно, ибо плохо продуманные блокировки — путь к deadlock.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 28.09.2017 7:59 · . Предыдущая версия .
Re[14]: Блокировки в бизнес-слое
От: Poul_Ko Казахстан  
Дата: 28.09.17 07:59
Оценка:
Здравствуйте, scf, Вы писали:
scf>Можно какой-нибудь пример из реальной жизни?
Давайте посмотрим что-то более приближенное к реальности.

Пусть те же самые заказы могут быть оплачены по договору юрлицом. Ссылка на договор указывается в заказе. Сам по себе договор является сложной сущностью, в нём заложены сложные ограничения на те товары, которые могут быть оплачены. Например, этот товар может, этот не может, а вот тот — в количестве не более 10 по данному договору (суммарно по всем сделанным заказам). Сам договор имеет период действия, и по нему могут быть оплачены только заказы, подтверждённые в этот период. Некий аналог страхового полиса в реальной жизни.
Бизнес-требование: в момент подтверждения заказа проверить все условия по договору (срок действия, ограничения по товарам), если что-то противоречит — заказ не подтверждается.
Все свойства договора — срок действия, ограничения — могут свободно редактироваться. Нельзя менять свойства так, что в итоге появятся подтверждённые заказы, противоречащие свойствам. На неподтверждённые начхать — они просто потом не подтвердятся.

Итак, мы пишем код для метода подтверждения заказа.
Первым делом вычитываем сущность договора, вторым — проверяем его срок действия и ограничения. Для проверки ограничений а-ля "не более 10 по данному договору" нужно ещё вычитать все другие заказы по этому договору на данных товар и просуммировать количество, чтобы понять сколько из 10 ещё можно.
Никто не будет отрицать, что во время всех этих проверок может быть выполнена другая операция, меняющая что-то из уже проверенного. Например, меняющая даты действия договора так, что обрабатываемый заказ в них не попадает. В этом случае мы получаем подтверждённый заказ, нарушающий условия договора.
Не будем же мы писать мелким шрифтом, как здесь предлагали, "Условия договора проверены неточно, перепроверьте ещё раз!" И перепроверять условия при отображении заказа — это тоже бред, я думаю все согласятся.

Вот вам реальная ситуация. Маловероятная, да, но реальная. Возможно да, "все переживут", но к сожалению решать это не разработчикам, а крайними окажутся именно они. Ведь требование есть, и формально ПО его не выполнило.
Brainbench transcript #6370594
Re[10]: Блокировки в бизнес-слое
От: Poul_Ko Казахстан  
Дата: 28.09.17 08:04
Оценка:
Здравствуйте, IB, Вы писали:

IB>Для этой проблемы другого решения нет.

IB>просто с транзакциями надо работать аккуратнее. Во-первых, Serializable не обязательно, до него обычно не доходит. А во-вторых, объем изменений в транзакции надо минимизировать, и все будет предсказуемо, без всяких дедлоков.
Надо, согласен. Но сложность растёт как снежный ком и это всё быстро выходит из под контроля, когда оно на уровне базы.
Похоже что требуется архитектурное решение, делающее по сути те же блокировки что умеет СУБД, но в терминах бизнес-слоя. Надеюсь что в итоге блокировки станут более предсказуемыми и обозримыми.
Brainbench transcript #6370594
Re[15]: Блокировки в бизнес-слое
От: · Великобритания  
Дата: 28.09.17 08:07
Оценка:
Здравствуйте, Poul_Ko, Вы писали:

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

Проверяется версия договора, которая загружена. А подтверждение заказа происходит только если его версия не изменилась. Операция меняющая даты действия договора — должна так же менять и версию:
UPDATE Agreement SET startDate = 'yesterday', Version = Version+1 WHERE id = 1


SQL выпоняет такой update атомарно. Твоя цель — свести большие сложные бизнес-операции, котоыре должны выполниться атомарно к элементарной атомарной sql-операции.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[12]: Блокировки в бизнес-слое
От: Poul_Ko Казахстан  
Дата: 28.09.17 08:10
Оценка:
Здравствуйте, ·, Вы писали:
·>Но тут надо очень осторожно, ибо плохо продуманные блокировки — путь к deadlock.

Дык на эти грабли уже наступили!
И пути теперь видим два — углубляться в базу, аккуратничать с блокировками и всегда это держать в уме (но это всё равно не решает проблемы если какие-то данные получены не из базы).
Либо перенести блокировки с базы на уровень выше — в бизнес-слой. Вот с целью ресёча такого решения я и затеял данную тему.
Brainbench transcript #6370594
Re[11]: Блокировки в бизнес-слое
От: Sinix  
Дата: 28.09.17 08:16
Оценка:
Здравствуйте, Poul_Ko, Вы писали:

P_K>То есть ваш вариант решения — пускай хранится неправильно, будем пересчитывать на каждый чих.

Неа, свой вариант я в самом начале привёл — храним ту цену, которую подтвердил покупатель, пока покупатель не подтвердил — вообще не храним.

P_K>Выглядит страшно и сложно

Да, разумеется. Так и задача непростая: вы храните по сути обещание (promise) и пытаетесь вместе с ним хранить актуальную стоимость. Подвох в том, что эта актуальная стоимость относится к некоторому заранее неизвестному моменту в будущем.
До некоторой стадии (заключения контракта) считать цену продажи вообще смыла нет. Всё, что можно — показать предварительную стоимость, которая может измениться в процессе финального оформления заказа (например, выбором одного из набора бонусов или добавлением индивидуальной скидки от менеджера).

P_K>Через блокировки я надеюсь что можно решить всё

Да, конечно, но с риском, что всё уткнётся в эту блокировку. Тут как всегда — или ищем компромисс, или тормозим

S>>Ну, т.е. возвращаемся к тому, с чего начали — при изменении большинства справочников придётся неоднократно пересчитать кучу заказов. Не самое лучшее решение.

P_K>Это недостаток данного примера. Считайте что куча небольшая и пересчёт не является чем-то тяжёлым.

Ну, тогда я бы сделал блокировку на уровне приложения для начала. Решение дубовое, но позволяет хоть примерно оценить общую производительность в худшем случае.
Re[16]: Блокировки в бизнес-слое
От: Poul_Ko Казахстан  
Дата: 28.09.17 08:22
Оценка:
Здравствуйте, ·, Вы писали:
·>Проверяется версия договора, которая загружена. А подтверждение заказа происходит только если его версия не изменилась. Операция меняющая даты действия договора — должна так же менять и версию:
·>
·>UPDATE Agreement SET startDate = 'yesterday', Version = Version+1 WHERE id = 1
·>

·>SQL выпоняет такой update атомарно. Твоя цель — свести большие сложные бизнес-операции, котоыре должны выполниться атомарно к элементарной атомарной sql-операции.

Не могу представить как это будет в реализации.
Ну вот подтверждаем мы заказ. Открыли транзакцию, прочитали договор, проверили — всё ок. Как теперь проверить что версия не изменилась? Вычитать договор из базы опять? Версия будет та же, если меняющая транзакция ещё не закоммитилась, она же идёт параллельно. И кто гарантирует что после такой проверки но перед коммитом никто не изменит договор?

Ну и когда я слышу "свести сложные бизнес-операции к элементарной sql-операции" что-то внутри меня переворачивается Бизнес-код должен решать бизнес-задачи, а не подстраиваться под возможности SQL.
Brainbench transcript #6370594
Re[12]: Блокировки в бизнес-слое
От: Poul_Ko Казахстан  
Дата: 28.09.17 08:30
Оценка:
Здравствуйте, Sinix, Вы писали:
S>Да, разумеется. Так и задача непростая: вы храните по сути обещание (promise)...
Пример был сильно упрощён. См. пример про подтверждение заказа и договор
Автор: Poul_Ko
Дата: 28.09.17
. Тут уже нет никакого "обещания" — мы либо считаем заказ соответствующим договору и подтверждаем, либо нет.

P_K>>Через блокировки я надеюсь что можно решить всё

S>Да, конечно, но с риском, что всё уткнётся в эту блокировку. Тут как всегда — или ищем компромисс, или тормозим
Ну вот и ищем
Brainbench transcript #6370594
Re[17]: Блокировки в бизнес-слое
От: XuMuK Россия  
Дата: 28.09.17 09:49
Оценка: +1
Здравствуйте, Poul_Ko, Вы писали:

P_K>Версия будет та же, если меняющая транзакция ещё не закоммитилась, она же идёт параллельно. И кто гарантирует что после такой проверки но перед коммитом никто не изменит договор?

Кмк, условия применения транзакций должны быть такими:
* для подтверждения договора — версия не изменилась.
* для изменения договора — договор остался в статусе неподтвержден и версия не изменилась.
В этом случае меняющая транзакция должа заканчиваться ошибкой, если договор в статусе "подтвержден" или был изменен параллельной транзакцией. Или можно увеличивать версию при подтверждении договора, тогда обе операции допустимы, если версия с начала операции не изменилась.
Re[13]: Блокировки в бизнес-слое
От: Sinix  
Дата: 28.09.17 10:04
Оценка:
Здравствуйте, Poul_Ko, Вы писали:

P_K>Пример был сильно упрощён. См. пример про подтверждение заказа и договор
Автор: Poul_Ko
Дата: 28.09.17
. Тут уже нет никакого "обещания" — мы либо считаем заказ соответствующим договору и подтверждаем, либо нет.

В этом случае всё элементарно. При подготовке заказа для подтверждения тем или иным способом делаем снапшот данных словарей, его и храним при подтверждении.
В 99% случаев с точки зрения бизнеса ситуация "цена поменялась за 20 минут до заключения договора" ничем не отличается от "цена поменялась через 20 минут после заключения".
В тех редких ситуациях, когда это не так, производится доппроверка перед заключением договора, которая уменьшает окно рассогласования до 2..3 минут.
В совсем отчаянных случаях коррекция цены (или расторжение договора) через отдельную бизнес-операцию.
Re[13]: Блокировки в бизнес-слое
От: · Великобритания  
Дата: 28.09.17 11:47
Оценка:
Здравствуйте, Poul_Ko, Вы писали:

P_K>·>Но тут надо очень осторожно, ибо плохо продуманные блокировки — путь к deadlock.

P_K>Дык на эти грабли уже наступили!
P_K>И пути теперь видим два — углубляться в базу, аккуратничать с блокировками и всегда это держать в уме (но это всё равно не решает проблемы если какие-то данные получены не из базы).
P_K>Либо перенести блокировки с базы на уровень выше — в бизнес-слой. Вот с целью ресёча такого решения я и затеял данную тему.
А кто обещал, что будет легко... Не зря же изобрели lock-free и прочее.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[17]: Блокировки в бизнес-слое
От: · Великобритания  
Дата: 28.09.17 12:06
Оценка:
Здравствуйте, Poul_Ko, Вы писали:

P_K>·>SQL выпоняет такой update атомарно. Твоя цель — свести большие сложные бизнес-операции, котоыре должны выполниться атомарно к элементарной атомарной sql-операции.

P_K>Не могу представить как это будет в реализации.
P_K>Ну вот подтверждаем мы заказ. Открыли транзакцию, прочитали договор, проверили — всё ок. Как теперь проверить что версия не изменилась? Вычитать договор из базы опять? Версия будет та же, если меняющая транзакция ещё не закоммитилась, она же идёт параллельно. И кто гарантирует что после такой проверки но перед коммитом никто не изменит договор?
Ну объяснил же уже вроде. Не просто проверка, а условная атомарная операция. Псевдокод:
SELECT Version, startDate...etc FROM Agreement WHERE id=1;
var CurrentVersion = Version;
// проверяем... долго и упорно
checkIt(startDate);
...
checkIt(etc);

// фиксируем
UPDATE Agreement SET Confirmed='YES' WHERE id=1 AND Version=CurrentVersion;
if(updatedRecords==0) rollback;// упс - облом, придётся начать сначала.

Ну и модифицирующие операции (все или как минимум те, которые могут влиять на проверки) должны изменять версию:
UPDATE Agreement SET startDate = 'yesterday', Version = Version+1 WHERE id = 1

ACID-ность UPDATE обеспечивается sql-сервером.

P_K>Ну и когда я слышу "свести сложные бизнес-операции к элементарной sql-операции" что-то внутри меня переворачивается Бизнес-код должен решать бизнес-задачи, а не подстраиваться под возможности SQL.

Я имел в виду обеспечить атомарность сложной бизнес-операции через атомарные sql-операции. Да, блокировка — способ обеспечения атомарности. Но не единственный.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 28.09.2017 14:05 · . Предыдущая версия .
Re[15]: Блокировки в бизнес-слое
От: scf  
Дата: 28.09.17 12:47
Оценка:
Здравствуйте, Poul_Ko, Вы писали:

P_K>Здравствуйте, scf, Вы писали:

scf>>Можно какой-нибудь пример из реальной жизни?
P_K>Давайте посмотрим что-то более приближенное к реальности.

P_K>Пусть те же самые заказы могут быть оплачены по договору юрлицом. Ссылка на договор указывается в заказе. Сам по себе договор является сложной сущностью, в нём заложены сложные ограничения на те товары, которые могут быть оплачены. Например, этот товар может, этот не может, а вот тот — в количестве не более 10 по данному договору (суммарно по всем сделанным заказам). Сам договор имеет период действия, и по нему могут быть оплачены только заказы, подтверждённые в этот период. Некий аналог страхового полиса в реальной жизни.

P_K>Бизнес-требование: в момент подтверждения заказа проверить все условия по договору (срок действия, ограничения по товарам), если что-то противоречит — заказ не подтверждается.
P_K>Все свойства договора — срок действия, ограничения — могут свободно редактироваться. Нельзя менять свойства так, что в итоге появятся подтверждённые заказы, противоречащие свойствам. На неподтверждённые начхать — они просто потом не подтвердятся.

P_K>Итак, мы пишем код для метода подтверждения заказа.

P_K>Первым делом вычитываем сущность договора, вторым — проверяем его срок действия и ограничения. Для проверки ограничений а-ля "не более 10 по данному договору" нужно ещё вычитать все другие заказы по этому договору на данных товар и просуммировать количество, чтобы понять сколько из 10 ещё можно.
P_K>Никто не будет отрицать, что во время всех этих проверок может быть выполнена другая операция, меняющая что-то из уже проверенного. Например, меняющая даты действия договора так, что обрабатываемый заказ в них не попадает. В этом случае мы получаем подтверждённый заказ, нарушающий условия договора.
P_K>Не будем же мы писать мелким шрифтом, как здесь предлагали, "Условия договора проверены неточно, перепроверьте ещё раз!" И перепроверять условия при отображении заказа — это тоже бред, я думаю все согласятся.

P_K>Вот вам реальная ситуация. Маловероятная, да, но реальная. Возможно да, "все переживут", но к сожалению решать это не разработчикам, а крайними окажутся именно они. Ведь требование есть, и формально ПО его не выполнило.


Похоже, что для надежного решения проблемы достаточно избавиться от COUNT() в коде подтверждения заказа. К примеру, хранить купленные лимиты прямо в договоре. Тогда хватит READ_COMMITED.

Еще один вариант — вести версионность договора. При модификации создается отдельная версия (кстати, редактирование активного договора выглядит странно, обычно к нему делают аддендумы), а заказы ссылаются на ту версию договора, с которой они были созданы.

Вообще всё это выглядит как еще один довод в пользу хранения сложных бизнес-объектов в базе в виде JSON. Помимо гибкости, и быстрых выборок/обновлений, мы получаем еще атомарные операции над бизнес-объектом с минимальным кол-вом локов.
Re: Блокировки в бизнес-слое
От: wildwind Россия  
Дата: 28.09.17 13:34
Оценка:
Здравствуйте, Poul_Ko, Вы писали:

P_K>Какие другие решения можете посоветовать?

P_K>Писать свой менеджер блокировок? Есть примеры?

Да, если это действительно оправдано. Примеры есть. Платформа 1С — там свой менеджер блокировок, в дополнение к блокировкам СУБД. Он позволяет заблокировать прикладной объект и обойтись одной блокировкой вместо множества строк в нескольких таблицах. Таким образом уменьшается количество блокировок в базе. Кроме того, возможны такие полезные вещи, как блокировка множества строк по условию. Например (если взять один из твоих примеров), у нас в таблице хранятся статусы заказов. И мы можем одной блокировкой заблокировать все неподтвержденные заказы одного клиента. Или даже группы клиентов. Если все это блокировать в базе, это будет медленно и тяжело для базы.

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

Ну и правильно реализовать такой менеджер непросто. Например, классическая проблема: когда отпускать блокировки зависшего/отвалившегося клиента?
Отредактировано 28.09.2017 13:36 wildwind . Предыдущая версия .
Re[11]: Блокировки в бизнес-слое
От: IB Австрия http://rsdn.ru
Дата: 28.09.17 20:16
Оценка: 1 (1)
Здравствуйте, Poul_Ko, Вы писали:


P_K>Надо, согласен. Но сложность растёт как снежный ком и это всё быстро выходит из под контроля, когда оно на уровне базы.

Если сложность растет от работы на уровне хранилища, значит вы что-то делаете не так, должно быть ровно наоборот.

P_K>Похоже что требуется архитектурное решение, делающее по сути те же блокировки что умеет СУБД, но в терминах бизнес-слоя. Надеюсь что в итоге блокировки станут более предсказуемыми и обозримыми.

Наоборот, в этом случае все вообще выйдет из под контроля, либо будет строго однопоточным и не масштабируемым. Хранилище — это единственное место где можно более-менее адекватно разрулить проблемы с синхонизацией данных.
В принципе, в каждой БД есть возможность воспользоваться механизмом блокировок для нужд прикладного слоя. Для сиквела это пара процедур sp_getapplock/sp_releaseapplock, но это ровно про то же самое, просто позволяет синхронизировать еще и сущности которые напрямую в БД не хранятся.
Мы уже победили, просто это еще не так заметно...
Re[2]: Блокировки в бизнес-слое
От: IB Австрия http://rsdn.ru
Дата: 28.09.17 20:25
Оценка:
Здравствуйте, wildwind, Вы писали:

W>Да, если это действительно оправдано. Примеры есть. Платформа 1С — там свой менеджер блокировок, в дополнение к блокировкам СУБД.

В 1С он не от хорошей жизни. Да и образцом правильной архитектуры 1С сложно назвать.

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

Для всего этого не нужно писать свой менеджер блокировок. В нормальных базах обычно предоставляется механизм позволяющий получить доступ к менеджеру блокировок базы и воспользоваться его услугами для блокировки прикладных объектов. Гораздо правильнее воспользоваться им, если уж возникнет такая нужда, чем городить собственный менеджер.

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

Отдельный плюс менеджера блокировок который встроен в БД состоит в том, что о нем знают транзакции БД.
Мы уже победили, просто это еще не так заметно...
Re[18]: Блокировки в бизнес-слое
От: Poul_Ko Казахстан  
Дата: 29.09.17 02:26
Оценка:
Здравствуйте, XuMuK, Вы писали:
P_K>>Версия будет та же, если меняющая транзакция ещё не закоммитилась, она же идёт параллельно. И кто гарантирует что после такой проверки но перед коммитом никто не изменит договор?
XMK>Кмк, условия применения транзакций должны быть такими:
XMK>* для подтверждения договора — версия не изменилась.
Что-то я потерял мысль...
Что вы понимаете под "условия применения транзакций"? Начало транзакции знаю, коммит и роллбэк знаю. Применение — это коммит?

"Подтверждения договора" — нет такого в бизнес-процессе, имелось в виду подтверждение заказа?
Как это будет выглядеть? Давайте в псевдокоде:
BeginTransaction();
var order = FindOrder();
var contract = FindContractForOrder(order);
VerifyContractConditions(contract, order);
order.Status = Confirmed; UpdateOrder(order);
if (GetActualContractVersion(contract.Id) == contract.Version) then CommitTransaction() else RollbackTransaction();

По идее вся последняя строчка должна отработать атомарно прямо на уровне базы, тогда решение будет рабочее, согласен. Но как её такую сделать?
Если же проверка версии и коммит это два отдельных запроса к базе, то это ничего не решит, между ними договор может поменяться.

XMK>* для изменения договора — договор остался в статусе неподтвержден и версия не изменилась.

XMK>В этом случае меняющая транзакция должа заканчиваться ошибкой, если договор в статусе "подтвержден" или был изменен параллельной транзакцией. Или можно увеличивать версию при подтверждении договора, тогда обе операции допустимы, если версия с начала операции не изменилась.
Стоп, у договора нет статуса, статус у заказа.
Brainbench transcript #6370594
Re[14]: Блокировки в бизнес-слое
От: Poul_Ko Казахстан  
Дата: 29.09.17 02:41
Оценка:
Здравствуйте, Sinix, Вы писали:
P_K>>Пример был сильно упрощён. См. пример про подтверждение заказа и договор
Автор: Poul_Ko
Дата: 28.09.17
. Тут уже нет никакого "обещания" — мы либо считаем заказ соответствующим договору и подтверждаем, либо нет.

S>В этом случае всё элементарно. При подготовке заказа для подтверждения тем или иным способом делаем снапшот данных словарей, его и храним при подтверждении.
Оно в принципе так и происходит, если я правильно понимаю вашу мысль.
В методе подтверждения вычитываются все нужные для проверки записи, они лежат в памяти, это и есть некий снэпшот, по ним работает логика. Логика отработала, заказ подтверждён, сохранён в базу, транзакция завершена, снапшот умер.
Или не то имелось в виду?

S>В 99% случаев с точки зрения бизнеса ситуация "цена поменялась за 20 минут до заключения договора" ничем не отличается от "цена поменялась через 20 минут после заключения".

По требованиям нет.
Условия меняются до подтверждения — изменённые условия будут проверены при подтверждении, заказ из-за этого может не подтвердиться — потребует дополнительного согласования в связи с изменением условия договора.
Условия меняются после подтверждения — если они противоречат уже подтверждённым заказам, то ПО отвергает изменения, юзеры должны сначала устранить проблему, например, отменить конфликтующие заказы. Но они должны это сделать явно.

S>В тех редких ситуациях, когда это не так, производится доппроверка перед заключением договора, которая уменьшает окно рассогласования до 2..3 минут.

Что такое "окно рассогласования"?

S>В совсем отчаянных случаях коррекция цены (или расторжение договора) через отдельную бизнес-операцию.

Это и есть отдельная бизнес-операция, со своими правилами.
При коррекции условий договора происходит проверка всех подтверждённых заказов по данному договору, если есть заказы, которые идут в разрез с новыми условиями, то коррекции не происходит, список показывается пользователю и бизнес-операция завершается. Пользователь должен исправить заказы и попытаться ещё раз изменить условия договора.
Brainbench transcript #6370594
Re[18]: Блокировки в бизнес-слое
От: Poul_Ko Казахстан  
Дата: 29.09.17 02:47
Оценка:
Здравствуйте, ·, Вы писали:
·>Ну объяснил же уже вроде. Не просто проверка, а условная атомарная операция. Псевдокод:
Agreement — очевидно это договор.
·>SELECT Version, startDate...etc FROM Agreement WHERE id=1;
·>var CurrentVersion = Version;
·>// проверяем... долго и упорно
·>checkIt(startDate);
·>...
·>checkIt(etc);

·>// фиксируем
// Почему  здесь Agreement? Подтверждаем-то мы заказ!
·>UPDATE Agreement SET Confirmed='YES' WHERE id=1 AND Version=CurrentVersion;
·>if(updatedRecords==0) rollback;// упс - облом, придётся начать сначала.


·>Ну и модифицирующие операции (все или как минимум те, которые могут влиять на проверки) должны изменять версию:

Это классика оптимистической блокировки, но работает она в пределах одного агрегата, а у нас здесь два (в реальности конечно больше)...
Brainbench transcript #6370594
Re[16]: Блокировки в бизнес-слое
От: Poul_Ko Казахстан  
Дата: 29.09.17 02:59
Оценка:
Здравствуйте, scf, Вы писали:

scf>Похоже, что для надежного решения проблемы достаточно избавиться от COUNT() в коде подтверждения заказа. К примеру, хранить купленные лимиты прямо в договоре. Тогда хватит READ_COMMITED.

Да, этим мы можем свести зависимости до двух сущностей — заказа и договора.
Проблема с количеством становится проблемой такого же порядка, как и проблема с датой действия. Да, решить её можно через READ_COMMITED.
В принципе это может быть первым шагом к решению проблемы — снизить уровни изоляции с SERIALIZABLE до READ_COMMITED, сначала выполнив замену всех подобных условий (на кол-во, существование) на проверку значения. Не уверен что такая замена всегда удастся, но возможно стоит попробовать.
Интересно бы узнать прогноз по такому решению — насколько станет легче? Станет ли сильно меньше дедлоков? Вряд ли кто-то скажет...
Ну и опять же это не решает проблемы с данными, получаемыми не из БД.

scf>Еще один вариант — вести версионность договора. При модификации создается отдельная версия (кстати, редактирование активного договора выглядит странно, обычно к нему делают аддендумы), а заказы ссылаются на ту версию договора, с которой они были созданы.

Такое решение должно быть принято бизнесом, а ему это не требуется.
Brainbench transcript #6370594
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.