Skip to content

fix(testcontainers): check master status in vshard readiness probe - #140

Open
NorthArea wants to merge 3 commits into
masterfrom
northarea/vshard-storages-ready-probe
Open

NorthArea wants to merge 3 commits into
masterfrom
northarea/vshard-storages-ready-probe

Conversation

@NorthArea

Copy link
Copy Markdown
Collaborator

The vshard readiness probe added in 1.7.0 (39e9dea) iterated rs.replicas, a field that vshard.router.info() does not return: vshard 0.1.25 reports master and replica per replicaset. The loop never ran, so VshardClusterContainer was reported ready while a replicaset master was still in the vshard handshake, and the first crud.truncate in spring-data integration tests failed with VHANDSHAKE_NOT_COMPLETE.

Seen in CI of #139: run 40517896080 (TarantoolTemplateViaJavaConfigTest) and run 40500876277 (RepositoryViaPropertiesTest), both in tests-crud-integration (3.5.0); both passed on rerun.

Why it fails only sometimes: it is a race between the vshard handshake and the first test request.

  • After connecting to a storage, the router sends vshard.storage._call('info') asynchronously and treats the connection as not ready until the reply arrives (vshard 0.1.25, vshard/replicaset.lua:120-130).
  • crud.truncate is a map call to all replicaset masters with is_async = true (crud 1.5.0, crud/common/call.lua:130). For async calls vshard does not wait for the handshake and fails at once with VHANDSHAKE_NOT_COMPLETE (vshard/replicaset.lua:576-588); sync calls do wait.
  • crud retries a map call only on MISSING_MASTER (crud 1.5.0, crud/common/call.lua:74-90), so the error goes straight to the test.
  • Whether the reply comes before the first truncate depends on how busy the storage is. On CI four storages and two routers share one container on the runner, and bootstrap is retried meanwhile (Duplicate key ... "_bucket" in the job log), so the outcome changes from run to run.
  • Why the handshake with storage-002-a was still incomplete tens of seconds after the container started in run 40517896080 is not established (possibly a router reconnect; router logs are not in the CI output). The fixed probe closes the window either way.

The probe now requires every replicaset master to be available, no replica to be unreachable, and no unreachable or unknown buckets.

Seen in CI of #139, tests-crud-integration (3.5.0), first attempt; both passed on rerun:

  • run 40517896080 — TarantoolTemplateViaJavaConfigTest.testKVTemplateUpdateById
  • run 40500876277 — RepositoryViaPropertiesTest.testPageablePageNumberGreaterCursor

Проверка готовности vshard из 1.7.0 (39e9dea) перебирала rs.replicas — поле, которого vshard.router.info() не возвращает: vshard 0.1.25 отдаёт по каждому репликасету master и replica. Цикл не выполнялся, и VshardClusterContainer объявлялся готовым, пока ведущий репликасета ещё проходил рукопожатие vshard. Первый crud.truncate в интеграционных тестах spring-data падал с VHANDSHAKE_NOT_COMPLETE.

Падения на CI #139: run 40517896080 (TarantoolTemplateViaJavaConfigTest) и run 40500876277 (RepositoryViaPropertiesTest), оба в tests-crud-integration (3.5.0); оба прошли при перезапуске.

Почему падает не каждый раз: это гонка между рукопожатием vshard и первым запросом теста.

  • Подключившись к хранилищу, роутер асинхронно отправляет vshard.storage._call('info') и считает соединение неготовым, пока не придёт ответ (vshard 0.1.25, vshard/replicaset.lua:120-130).
  • crud.truncate — рассылка на ведущие всех репликасетов с is_async = true (crud 1.5.0, crud/common/call.lua:130). Для асинхронных вызовов vshard рукопожатия не ждёт и сразу возвращает VHANDSHAKE_NOT_COMPLETE (vshard/replicaset.lua:576-588); синхронные вызовы ждут.
  • crud повторяет рассылку только при MISSING_MASTER (crud 1.5.0, crud/common/call.lua:74-90), поэтому ошибка сразу уходит в тест.
  • Успеет ли ответ до первого truncate, зависит от загрузки хранилища. На CI четыре хранилища и два роутера работают в одном контейнере на общем раннере, а начальная раскладка данных (bootstrap) в это время идёт с повторами (Duplicate key ... "_bucket" в логе задания), поэтому исход от прогона к прогону разный.
  • Почему в run 40517896080 рукопожатие с storage-002-a не завершилось и через десятки секунд после старта контейнера, не установлено (возможно, роутер переподключался; журналов роутера в выводе CI нет). Исправленная проверка закрывает это окно в любом случае.

Теперь проверка требует: ведущий каждого репликасета — available, ни одной реплики unreachable, нет недоступных и неизвестных бакетов.

Падения на CI #139, tests-crud-integration (3.5.0), первая попытка; оба прошли при перезапуске:

  • run 40517896080 — TarantoolTemplateViaJavaConfigTest.testKVTemplateUpdateById
  • run 40500876277 — RepositoryViaPropertiesTest.testPageablePageNumberGreaterCursor

I haven't forgotten about:

  • Tests — no new test: the change is in test infrastructure; verified by the integration jobs of this PR
  • Changelog
  • Documentation
  • JavaDoc was written
  • Commit messages comply with the guideline
  • Cleanup the code for review. See checklist

Related issues:
See also #139

Aleksandr Iuskasov added 3 commits October 28, 2026 12:32
The probe added in 1.7.0 iterated `rs.replicas`, a field that
`vshard.router.info()` does not return (vshard 0.1.25 reports `master`
and `replica` per replicaset). The loop never ran, so the container was
reported ready while a replicaset master was still in the vshard
handshake, and the first `crud.truncate` in spring-data integration
tests failed with VHANDSHAKE_NOT_COMPLETE.

Require every replicaset master to be `available`, no replica to be
`unreachable`, and no unreachable or unknown buckets.
The previous probe also required no `unreachable` replica and zero
unknown buckets. In CI (tests-crud-integration 3.5.0, job 122708866002)
it returned false for the whole 120 s window in
RepositoryViaJavaConfigTest while bootstrap had succeeded, so the
container failed to start.

Requiring only an `available` master is not enough either. On a stand
the router state stayed `storage-002 master=unreachable
replica=available` for 120 s: the router connected to storage-002-a
before its storage was configured, the vshard handshake failed with
"storage is not configured", and vshard closed the connection
(vshard/replicaset.lua conn_vconnect_check_or_close). Only a request to
that master reopens it, and discovery and failover talk to the replica.
The first asynchronous crud map call reopens it but does not wait for
the new handshake, which is the VHANDSHAKE_NOT_COMPLETE seen in #139.

Make a synchronous `callrw('vshard.storage.buckets_count')` to the
master of every replicaset: it reopens a closed connection and waits for
the handshake. Require all calls to succeed and every master to be
`available`, and log call errors, replica and bucket states.
checks 287c88e ("exclude nil function name from error messages",
2026-10-28) drops the " to nil" suffix from "unexpected argument"
errors. crud 1.5.0 depends on `checks >= 3.1.0-1`, so the test cluster
picks it up on every fresh build, and testSelectWrongParameters fails
on master with "... select.lua:320: unexpected argument opts.coolOption".

Accept the message with and without the suffix.

(cherry picked from commit 52700595fa36ebb3c0d0de569438bc636a93e1f0)

This branch has not been deployed

No deployments
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.

1 participant