Skip to main content
Статус: принято.

Контекст

Omniflow продаёт доступ, который выдаёт Remnawave. Поэтому две системы хранят внешне пересекающиеся факты об одном клиенте: Omniflow знает, за что заплачено, а Remnawave знает, что сейчас верно для пользователя VPN — израсходованный трафик, подключённые устройства, срок действия, состав отрядов и то, правил ли это оператор руками сегодня утром. Сделать из этого одну систему можно двумя способами. Omniflow мог бы обращаться с базой Remnawave как со своей и писать в неё напрямую — это быстро. Или он мог бы зеркалировать состояние Remnawave в свои таблицы и считать зеркало истиной — это аккуратно. Оба варианта ломаются одинаково: как только кто-то что-то меняет в панели Remnawave, системы расходятся, и ничто в конструкции не говорит, какая из них неправа.

Решение

Remnawave авторитетен для пользователей VPN, трафика, устройств, ссылок доступа, узлов, хостов, отрядов и состояния Xray. Omniflow никогда не пишет в хранилище Remnawave, не управляет Xray и обращается к панели только через версионированный адаптер по её поддерживаемому API. Omniflow хранит право на услугу: то, на что оплаченный заказ даёт клиенту право. Это запись, отдельная от наблюдаемого состояния Remnawave, и связаны они ровно одной ссылкой. При расхождении оно записывается как drift с причиной, которую оператор может прочитать, а не разрешается молча в одну из сторон. Любая запись — это операция выдачи: идемпотентная, повторяемая с задержкой, когда Remnawave недоступен, и связанная с заказом, который её оправдал.

Последствия

Деньги и доступ отказывают независимо — ради этого свойства и построена вся конструкция. Успешная оплата никогда не теряется из-за того, что Remnawave лежит: она фиксируется, а задание выдачи продолжает попытки. Оператор, правящий пользователя в панели Remnawave, порождает drift для разбора, а не молчаливую перезапись при следующей синхронизации. Цена — целая поверхность сверки, которая не понадобилась бы конструкции с одной базой: обнаружение расхождений, их причины, экран для оператора и безопасная обработка пользователей Remnawave, отредактированных или удалённых вне Omniflow. Эта механика — не случайная сложность, а видимая форма того факта, что двум системам принадлежат разные половины одного продукта. Это также означает, что на часть вопросов Omniflow не может ответить, не спросив Remnawave. Списки устройств и текущий трафик запрашиваются, а не хранятся, поэтому они зависят от доступности Remnawave, и поэтому у клиентских поверхностей есть явные состояния «устарело» и «недоступно». Совместимость ограничена тем, что реально проверяют контрактные тесты, — сейчас это поверхность API Remnawave 3.2.x. Версия вне этого диапазона не поддерживается, а не «не проверена, но, наверное, работает».

Когда пересматривать

  • Поддерживаемый API Remnawave перестаёт предлагать операцию, нужную Omniflow, и альтернативы — только писать в его хранилище или отказаться от возможности. Верным исходом всё равно остаётся не писать в его хранилище.
  • Будущая мажорная версия Remnawave меняет само разделение владения — например, забирает биллинг; тогда эта запись заменяется, а не правится.

Смежное

  • Владение данными — полное разделение и что ломается при его нарушении.
  • Remnawave — каждый вызов, который делает Omniflow, и граница, которую он не пересекает.
  • Выдача доступа — как намерение становится выданным доступом.