Комментарии 15
А что такое " "два стула" "?
Это отсылка к известному выражению «усидеть на двух стульях». Оно описывает попытку совместить две разные, порой противоречивые вещи, рискуя в итоге не получить ни одной.
В нашем случае, эти «два стула» - это два наших хранилища данных, каждое со своей, уникальной задачей:
Первый стул - блокчейн Solana. Это наш «стул» неизменности и гарантий.
Второй стул - PostgreSQL. Это наш «стул» скорости и удобства.
Вся статья по сути о том как опасно сидеть «между» этими стульями. Что делать, если мы успешно «сели» на первый стул (записали транзакцию в Solana), но «пошатнулись» на втором (запись в PostgreSQL сорвалась из-за ошибки)? В этот самый момент и возникает рассинхрон — главная проблема, с которой мы боремся.
А что если запись в блокчейн пройдет успешно, а в момент коммита транзакции получим ошибку? Ведь изначальная проблема остается
Cбой на этапе коммита это реальный риск для любой базы данных.
К счастью, здесь нам на помощь приходят гарантии транзакционной системы самой PostgreSQL.
Если COMMIT не прошел (из-за сбоя сети, падения БД, проблем с диском), база данных сама откатит всю транзакцию целиком. Это означает, что ни запись о дипломе, ни событие в outbox_events не будут сохранены. С точки зрения системы, операция просто не удалась. Пользователь получит ошибку, попробует еще раз, и мы не получим рассинхрона.
Если COMMIT прошел, СУБД гарантирует, что данные записаны на диск (согласно уровню durability). Даже если сервис упадет через миллисекунду после этого, обе записи (диплом и событие в outbox) уже будут в базе.
Таким образом, благодаря атомарности транзакции в PostgreSQL, мы избегаем состояния "частичной записи". У нас либо обе записи успешно сохранены, либо ни одной. Изначальная проблема "запись в блокчейн есть, а в БД нет" решена, так как запись в блокчейн теперь происходит асинхронно и только после успешного коммита в БД.
Статья ллм'кой написана
И даже в комментариях отвечает ллм
Сколько будет два стула плюс два стула ?
Забавно, но я воспринимаю это как комплимент качеству структуры и текста. В эпоху, когда LLM становятся все лучше, грань стирается. Главное, чтобы материал был полезен, решал реальную проблему и вызывал дискуссию, не так ли?
Не комплимент
Вы сейчас не содержание текста обсуждаете, а придумываете его происхождение. Когда будут реальные аргументы - приходите.
Аргумент - типовой текст от ллм не несёт ценности
Вы всё ещё не привели ни одного технического замечания.
Пока что единственная “экспертиза”, которую вы демонстрируете - это умение заметить слово “LLM” и начать на нём ехать, вместо анализа сути.
Для человека, который позиционирует себя как Go-разработчик, странно видеть попытку уйти от инженерного разговора к гаданию на происхождении текста.
Обычно так делают те, кому нечего сказать по сути.
Если вы хотите выглядеть экспертом - предъявите конкретные факты, ошибки, кейсы, сравнения, а не попытку спрятать отсутствие аргументов за фразой “типовой текст”.
Пока что ваш вклад в дискуссию выглядит намного слабее даже самого среднего ответа LLM.
Вам действительно интересно подискутировать на тему статьи ?
Если реально интересно и если это ваш реальный опыт
Аутбокс - норм тема, проверять его и все что дальше это оверхэд
Аутбокс просто повторит попытку записи через какое то время
В какую базу писать первой наверное нет разницы, но я бы писал в постгрю, там acid
Мониторинг можно добавить, это гуд
Очередь добавлять-оверхэд
Сага - вообще антипаттерн, означает что система неправильно декомпозирована, из за чего и пришлось сагу писать
Звучит как высосанная из пальца проблема. Кто мешает писать в постгреc, а потом в блокчейн и юзать обычный сага паттерн? Тогда все прекрасно откатывается
Вы затронули самый корень архитектурной дилеммы, и это именно тот вопрос, который мы задавали себе на старте. Давайте разберем предложенный вами флоу, который, по сути, и является паттерном Saga, описанным в статье.
Флоу "Сначала Postgres, потом Solana" (Saga):
Начинаем локальную транзакцию в Postgres, сохраняем диплом со статусом PENDING. Коммитим.
Отправляем транзакцию в Solana.
Теперь рассмотрим точки отказа:
Сценарий 1 (простой): Отправка в Solana не удалась. Что мы делаем? Компенсирующую транзакцию: обновляем статус в Postgres на FAILED. Пока все выглядит неплохо и действительно откатывается.
Сценарий 2 (коварный): Транзакция в Solana прошла успешно, но наш сервис падает до того, как он успел обновить статус в Postgres на CONFIRMED.
И вот здесь мы получаем тот же самый рассинхрон, только в обратную сторону: в блокчейне запись есть, а в нашей базе она навсегда осталась в статусе PENDING. Для исправления этого нам понадобится тот самый Reconciliation Job, который будет сверять записи и исправлять такие "подвисшие" состояния.
Но ключевая проблема в вашем тезисе - «все прекрасно откатывается» - не работает с блокчейном. Если транзакция в Solana прошла (сценарий 2), ее невозможно откатить. Можно только сделать новую транзакцию, которая логически ее аннулирует, но это:
а) сложно (нужно хранить состояние, чтобы знать, что аннулировать),
б) усложняет модель данных (появляются отмененные записи),
в) стоит реальных денег (газ).Именно поэтому Transactional Outbox оказывается надежнее в этом контексте. Он атомарно гарантирует, что задача "отправить в Solana" будет создана. А отдельный воркер потом надежно, с повторными попытками, выполнит эту задачу, защищая нас от сбоев самого сервиса-отправителя.
Так что проблема не высосана из пальца, а является фундаментальным компромиссом при работе с необратимыми внешними системами.

«Два стула» для данных: как мы боремся с рассинхроном в Rust-сервисе между Solana и PostgreSQL