Да здравствует указатель на функцию
Apr. 4th, 2020 06:42 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
В своем текущем поделии как разумный человек я вынес всю работу с базой в отдельный модуль. И фоновые задачи у меня тоже живут в отдельном от вебинтерфейса модуле.
И тут возникла проблема. Как часто бывает, некоторую часть реализации бизнес-логики надо делать в контексте одной SQL-транзакции (SELECT FOR UPDATE + UPDATE). И тут получается, что либо надо затаскивать транзакцию в логику (до свидания, инкапсуляция БД), либо совать сложную логику в контекст работы с базой (нечего ей там делать). И кольцевые импорты опять же.
Но тут, раз все равно работаю с асинхронщиной, решение пришло практически само. При вызове функции работы с БД ей в т.ч. передается коллбэк родом из модуля фоновых задач. Инкапсуляция на месте, кольцевых импортов нет, и пастуху вечная память.
Да, чтобы два раза не вставать. Как только у вас вместо долгого и задумчивого 201 Created появляется быстрый и резкий 202 Accepted, у вас сразу же возникают проблемы с внутренней консистентностью, которую надо решать. Грубо говоря, из двух действий: "сделать что-то" и "записать, что сделал что-то" вы всегда сначала делаете одно, а потом другое, и вот если панночка померла аккурат между ними, то у вас неконсистентность. В сколь-нибудь распределенной системе, в которой есть сколь-нибудь долгие процессы, панночка будет регулярно помирать именно в этой позе.
И тут возникла проблема. Как часто бывает, некоторую часть реализации бизнес-логики надо делать в контексте одной SQL-транзакции (SELECT FOR UPDATE + UPDATE). И тут получается, что либо надо затаскивать транзакцию в логику (до свидания, инкапсуляция БД), либо совать сложную логику в контекст работы с базой (нечего ей там делать). И кольцевые импорты опять же.
Но тут, раз все равно работаю с асинхронщиной, решение пришло практически само. При вызове функции работы с БД ей в т.ч. передается коллбэк родом из модуля фоновых задач. Инкапсуляция на месте, кольцевых импортов нет, и пастуху вечная память.
Да, чтобы два раза не вставать. Как только у вас вместо долгого и задумчивого 201 Created появляется быстрый и резкий 202 Accepted, у вас сразу же возникают проблемы с внутренней консистентностью, которую надо решать. Грубо говоря, из двух действий: "сделать что-то" и "записать, что сделал что-то" вы всегда сначала делаете одно, а потом другое, и вот если панночка померла аккурат между ними, то у вас неконсистентность. В сколь-нибудь распределенной системе, в которой есть сколь-нибудь долгие процессы, панночка будет регулярно помирать именно в этой позе.
(no subject)
Date: 2020-04-04 04:23 pm (UTC)С внутренней консистентностью проблема возникает, если надо как-то провзаимодействовать с внешним миром (письмо отправить или к сервису стукнуться). Да, неконсистентность тут запросто вылезет, ну а дальше вопрос про частоту отвала того сервиса. Может, проще ручками устранить раз в неделю, что мы запрос послали, сервер его отработал, а коннект оторвался. Ну а пользователь всяко перетопчется, если получит 2 письма вместо одного.
(no subject)
Date: 2020-04-05 04:26 am (UTC)1. Записал конфиг для сервиса.
2. Дернул сервис.
3. Получил коллбэк от сервиса.
4. Записал, что сервис рапортовал о завершении.
И вот если на п.3 приклад был по какой-то причине мертвенький, то все плохо. Значит, надо на стороне внешнего сервиса городить ретраи.
Вообще, конечно, логика at least once и at most once реализуется тривиально (пнул, записал и записал, пнул). Вот exactly once - это сложнее.
Правда, на этом этапе мы вполне переживаем ситуацию: "когда приклад сдох, у него три задачи висело в неконсистентном состоянии; оператор, сходи в логи внешних сервисов и руками закрой или поретрай".
(no subject)
Date: 2020-04-05 11:14 am (UTC)(no subject)
Date: 2020-04-04 06:57 pm (UTC)Так оно получится как dynamic sql, что геморойно, но вполне реализуемо
(no subject)
Date: 2020-04-05 04:12 pm (UTC)(no subject)
Date: 2020-04-05 05:03 pm (UTC)