ydb-platform / ydb-platform/ydb-php-sdk
bug: сессия становится непригодной после любой неудачной DML-операции (tx_id не сбрасывается)
Nobody has claimed this yet.
- 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:
- Создать таблицу с PRIMARY KEY.
$session->query('INSERT INTO t (id) VALUES (1)')— успешно.- Тот же INSERT ещё раз (конфликт по PK) — ожидаемо падает с
PRECONDITION_FAILED. - Любой следующий запрос на этой же сессии — падает с
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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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