ydb-platform / ydb-platform/ydb-php-sdk

bug: сессия становится непригодной после любой неудачной DML-операции (tx_id не сбрасывается)

Open
#273 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
PHP
Stars
39
Forks
19
Avg merge
1d 15h
Merged PRs (30d)
2

Description

Bug Report

YDB PHP SDK version:

Актуальный main (проверено на коммите перед 44e3bcc, баг не зависит от версии — воспроизводится стабильно).

Environment

PHP 8.2–8.5 (проверено на всех четырёх версиях), YDB в Docker (cr.yandex/yc/yandex-docker-local-ydb:latest). От окружения не зависит — баг в логике SDK, воспроизводится на любом YDB.

Current behavior:

После любой неудачной DML-операции на сессии (например, INSERT с конфликтом по PRIMARY KEY) любой следующий запрос на этой же сессии падает с YDB_400140 NOT_FOUND: Transaction not found: <id> — даже если ни один явный beginTransaction() не вызывался. Единственный способ восстановить сессию — пересоздать её.

Причина: Session::query() переиспользует внутренний tx_id между вызовами и открывает новую транзакцию только когда он null, но никогда не сбрасывает tx_id после неудачного запроса — сессия продолжает переиспользовать транзакцию, которую сервер уже отменил.

Очевидный обходной путь — вызвать $session->rollBack() после ошибки — тоже не работает: commitTransaction() и rollbackTransaction() сбрасывают tx_id только после успешного собственного RPC-вызова, а он обязательно падает именно потому, что транзакция уже мертва.

Expected behavior:

Неудачный query() (а также commit()/rollBack(), если их RPC-вызов сам падает) должен сбрасывать tx_id, чтобы следующий вызов на той же сессии открывал новую транзакцию, а не переиспользовал мёртвую.

Steps to reproduce:

  1. Создать таблицу с PRIMARY KEY.
  2. $session->query('INSERT INTO t (id) VALUES (1)') — успешно.
  3. Тот же INSERT ещё раз (конфликт по PK) — ожидаемо падает с PRECONDITION_FAILED.
  4. Любой следующий запрос на этой же сессии — падает с NOT_FOUND: Transaction not found, хотя beginTransaction()/commit()/rollBack() явно не вызывались.

Related code:

src/Session.php: query(), commitTransaction(), rollbackTransaction().

Other information:

Уже есть готовый фикс: #272. Решение сверено с поведением официальных Python (ydb/_tx_ctx_impl.py::reset_tx_id_handler, TxState.dead) и Java (BaseSession, setNewId(currentId, null) в executeDataQuery) SDK — оба явно сбрасывают состояние транзакции в момент ошибки запроса, а не только в commit/rollback. Баг найден при разработке ydb-doctrine (Doctrine DBAL-драйвер для YDB).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/Session.php, focusing on query(), commitTransaction(), and rollbackTransaction(), then reproduce the failed DML sequence described in the issue. Check how tx_id is handled when each RPC call fails. Done means a failed operation clears the transaction state so the next query on the same session can proceed with a new transaction.

Written by the indexing model from the issue text.

Assessment

Tech stack
php
Domain
databases
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.