Skip to content

fix(tarantool-core): send IPROTO_WATCH after authentication - #126

Merged
dkasimovskiy merged 7 commits into
masterfrom
fix-watch-before-auth
Sep 25, 2026
Merged

dkasimovskiy merged 7 commits into
masterfrom
fix-watch-before-auth

Conversation

@dkasimovskiy

@dkasimovskiy dkasimovskiy commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Суть

Сейчас при gracefulShutdown = true клиент отправляет IPROTO_WATCH до IPROTO_AUTH. Для Tarantool EE с включенной опцией security.disable_guest: true сервер отвечает ER_AUTH_REQUIRED, соединение не устанавливается и циклически переподключается каждую секунду.

Регрессия версии 1.7.0 (#102): до неё ошибка watcher не влияла на подключение.

Решение

Регистрация watcher'ов построена по принципу error-driven: ошибка ER_AUTH_REQUIRED обрабатывается не как сбой, а как сигнал «отложить до авторизации».

Поток выполнения:

  1. IProtoClientImpl.connect() отправляет watcher'ы сразу после установления соединения, как и раньше.
  2. Если сервер отвечает ER_AUTH_REQUIRED (код 258), WatcherStateMachine не вызывает error handler, а передаёт управление коллбеку, который сбрасывает состояние failed watcher'а и убирает его FSM из реестра.
  3. IProtoClientImpl.authorize() после успешной аутентификации вызывает updateWatchers(), повторно регистрируя все отложенные watcher'и — теперь сервер принимает их.

Таким образом, при disable_guest: true подписки регистрируются только после завершения authorize(), а при гостевом доступе (без авторизации) — сразу в connect().

Запросы, доступные до аутентификации

Tarantool допускает до аутентификации только ограниченный набор IPROTO-запросов:

  • AUTH — собственно аутентификация;
  • PING — используется для guest-подключения и heartbeat;
  • ID — обмен версиями и фичами протокола;
  • VOTE — голосование в репликации.

Любой другой запрос (включая WATCH) при disable_guest: true отклоняется с ER_AUTH_REQUIRED. Поэтому box.shutdown watcher при gracefulShutdown нельзя зарегистрировать сразу после greeting — его регистрация откладывается до завершения authorize().

@dkasimovskiy
dkasimovskiy force-pushed the fix-watch-before-auth branch 2 times, most recently from 8925591 to f42f64a Compare September 24, 2026 08:08
Comment thread tarantool-core/src/main/java/io/tarantool/core/IProtoClientImpl.java Outdated
IProtoClientWatchersTest uses connect() without auth. Since watchers
are now sent after ping() (TNTP-10388 fix), ping must be called to
trigger watcher registration.
- testAuthorization: auth response syncId is now 2 since IPROTO_WATCH
  is no longer allocated before the auth request (TNTP-10388)
- testWatcherRecoveryAfterReconnect: call ping() after reconnect to
  re-trigger watcher registration, adjust sleep timings
// it does not send watch message if connection is not connected,
// it sends immediately after successful connect
// the watch request is sent later, after authorize() or ping()
watch(SHUTDOWN_EVENT_KEY, this::shutdownEventCallback);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Запрос на регистрацию этого watcher требует зарегистрированного пользователя? Если да, то это тоже надо делать после того, как произошел autorize()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Да, требует. Этот watcher регистрируется тем же механизмом: отправляется при подключении, а если сервер отклоняет его до авторизации — откладывается и перерегистрируется после authorize().

}

@Override
public CompletableFuture<IProtoResponse> authorize(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Решение, когда впускать вотчеры должно решаться не здесь, а выше по вызову

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authorize() — часть публичного API клиента, поэтому именно здесь гарантируется перерегистрация отложенных watcher'ов для прямых вызовов connect() → authorize(). Гостевой сценарий (без authorize()) обрабатывается отдельно — watcher'ы регистрируются сразу после подключения.

Fallback to set watchers after authentication if ER_AUTH_REQUIRED happens on connect.

@dkasimovskiy dkasimovskiy left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bitgorbovsky error-driven подход уже реализован — на ER_AUTH_REQUIRED watcher отправляет onAuthRequired коллбек, который сбрасывает failed state. После authorize() -> updateWatchers() все отложенные watcher'и перереgistруются. ping без updateWatchers — оверхед heartbeat закрыт.

@dkasimovskiy
dkasimovskiy merged commit 6fcb8e9 into master Sep 25, 2026
14 of 16 checks passed
@dkasimovskiy
dkasimovskiy deleted the fix-watch-before-auth branch September 25, 2026 12:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants