Синхронный QueryClient с более удобным API #342
Gazizonoki
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Дизайн TQueryClient
Текущий Query Client - это низкоуровневый интерфейс, который дает пользователю TSession и TTxControl для прямого использования, вводит обработку ошибок через TStatus. Это приводит к boilerplate'у у пользователя. Также при синхронном использовании асинхронного API TQueryClient получается колбаса из вызовов функций.
Такой интерфейс может быть актуален в очень высоконагруженных приложениях, где нужен ручной контроль, но большинству пользователей он создает только лишние сложности. Поэтому предлагается:
Сделать синхронный клиент, более дружелюбный к пользователю для решения большинства задач пользователя:
NYdb::NQuerySync::TQueryClient.Порефакторить текущий API асинхронного клиента, чтобы он тоже был ближе к API синхронного клиента.
В синхронном клиенте:
TDbRequestError.TRetryHandleTTxControlтранзакция создается с объектомTTransactionи действует на протяжении его лайфтайма. (Как в libpqxx)В aсинхронном клиенте:
TTxControldeprecatedRetryQueryс клиентом в качестве объекта ретрая deprecatedExecuteQuery()на клиенте использовать явную сессию из пулаExecuteQuery()на объекте транзакции{% list tabs %}
Старый клиент
Новый синхронный клиент
Новый асинхронный клиент
{% endlist %}
Один запрос в транзакции (на явной сессии)
При выполнении запроса на синхронном клиенте используется явная сессия из пула, а не посылается запрос с пустым session id (неявная сессия). Такой запрос исполняется в одной транзакции, настройки транзакции (TTxSettings) - опциональный параметр.
{% list tabs %}
Старый клиент
TDriver driver{"grpc://localhost:2136/?database=local"}; TQueryClient client{driver}; auto getSessRes = client.GetSession().GetValueSync(); if (!getSessRes.IsSuccess()) { std::cerr << ToString(getSessRes); } auto session = getSessRes.GetSession(); auto result = session.ExecuteQuery("SELECT 1;", TTxControl::BeginTx().CommitTx()).GetValueSync(); if (!result.IsSuccess()) { std::cerr << ToString(result); } // parse resultНовый синхронный клиент
TDriver driver{"grpc://localhost:2136/local"}; TQueryClient client{driver}; try { auto result = client.ExecuteQuery("SELECT 1;"); // parse result } catch (NYdb::TDbRequestError& e) { std::cerr << e; }{% endlist %}
Асинхронный запрос
При выполнении запроса на асинхронном клиенте теперь также используется явная сессия из пула. Поэтому этап получения сессии можно пропустить. Запрос будет исполнен в 1 транзакции, настройки можно передать через опциональный параметр.
{% list tabs %}
Старый клиент
TDriver driver{"grpc://localhost:2136/?database=local"}; TQueryClient client{driver}; auto asyncStatus = client.GetSession().Apply([](auto result) -> TStatus { if (!result.GetValue().IsSuccess()) { return result; } auto session = result.GetValue().GetSession(); return session.ExecuteQuery("SELECT 1;", TTxControl::BeginTx().CommitTx()).Apply([](auto result) -> TStatus { if (!result.GetValue().IsSuccess()) { return result; } // parse result }); }); //////////////////////////////////////////////////////// auto status = asyncStatus.GetValueSync(); if (!status.IsSuccess()) { std::cerr << ToString(status); }Новый aсинхронный клиент
TDriver driver{"grpc://localhost:2136/local"}; TQueryClient client{driver}; auto asyncStatus = client.ExecuteQuery("SELECT 1;").Apply([](auto result) -> TStatus { if (!result.GetValue().IsSuccess()) { return result; } // parse result }); //////////////////////////////////////////////////////// auto status = asyncStatus.GetValueSync(); if (!status.IsSuccess()) { std::cerr << ToString(status); }{% endlist %}
Ретрай запроса
Раньше ретраить можно было либо на клиенте (неявные сессии), либо на сессии.
В синхронном клиенте теперь ретраи можно делать только через
TRetryHandle. Это некопируемый и неперемещаемый объект, инициализируется сессией и все запросы перенаправляет в нее.{% list tabs %}
Старый клиент
TDriver driver{"grpc://localhost:2136/?database=local"}; TQueryClient client{driver}; auto result = client.RetryQuery([](TSession session) { return session.ExecuteQuery("SELECT 1;", TTxControl::BeginTx().CommitTx()); }).GetValueSync(); if (!result.IsSuccess()) { std::cerr << ToString(result); } // parse resultНовый синхронный клиент
TDriver driver{"grpc://localhost:2136/local"}; TQueryClient client{driver}; try { client.RetryQuery([](TRetryHandle& handle) { auto result = handle.ExecuteQuery("SELECT 1;"); // parse result }); } catch (NYdb::TDbRequestError& e) { std::cerr << e; }{% endlist %}
Интерактивная транзакция
Для интерактивной транзакции используется объект TTransaction. Он некопируемый и неперемещаемый. Семантика у него такая же, как у транзакции в libpqxx, транзакция активна в переделах скоупа этого объекта. В деструкторе вызывается
Rollback(). ЕслиRollback()завершился ошибкой, сессия выкидывается из пула.Сделать коммит можно 2 способами - явный вызов
Commit()или передав Commit флаг в настройках. Во втором случае в запросе будет переданTTxControl::Tx().Commit().Для удобства объект транзакции можно создать вызовом метода
BeginTransaction()прямо из клиента иTRetryHandle. ДляBeginTransaction()можно выставить режим неявного начала транзакции. Тогда в первом запросеExecuteQuery()будет переданTTxControl::BeginTx().BeginTransaction()можно сделать сразу на клиенте. Тогда будет использована сессия из пула.{% list tabs %}
Старый клиент
TDriver driver{"grpc://localhost:2136/?database=local"}; TQueryClient client{driver}; auto getSessRes = client.GetSession().GetValueSync(); if (!getSessRes.IsSuccess()) { std::cerr << ToString(getSessRes); } auto session = getSessRes.GetSession(); auto result1 = session.ExecuteQuery("SELECT 1;", TTxControl::BeginTx()).GetValueSync(); if (!result1.IsSuccess()) { std::cerr << ToString(result1); } // parse result auto result2 = session.ExecuteQuery("SELECT 2;", TTxControl::Tx(result.GetTransaction()).CommitTx()).GetValueSync(); if (!result2.IsSuccess()) { std::cerr << ToString(result2); } // parse resultНовый синхронный клиент
TDriver driver{"grpc://localhost:2136/local"}; TQueryClient client{driver}; try { auto tx = client.BeginTransaction(); auto result1 = tx.ExecuteQuery("SELECT 1;"); // parse result auto result2 = tx.ExecuteQuery("SELECT 2;", {}, ExecuteInTxSettings().Commit()); // parse result } catch (NYdb::TDbRequestError& e) { std::cerr << e; }{% endlist %}
Асинхронная интерактивная транзакция
В отличие от старого клиента, новый будет создавать транзакции только через
BeginTransaction(). В нем можно выставить режим неявного начала транзакции. Тогда в первом запросеExecuteQuery()будет переданTTxControl::BeginTx(). Запросы выполняются через объект транзакции.Сделать коммит можно 2 способами - явный вызов
Commit()или передав Commit флаг в настройках. Во втором случае в запросе будет переданTTxControl::Tx().Commit().BeginTransaction()можно сделать сразу на клиенте. Тогда будет использована сессия из пула.{% list tabs %}
Старый клиент
TDriver driver{"grpc://localhost:2136/?database=local"}; TQueryClient client{driver}; auto asyncStatus = client.GetSession().Apply([](auto result) -> TStatus { if (!result.GetValue().IsSuccess()) { return result; } auto session = result.GetValue().GetSession(); return session.ExecuteQuery("SELECT 1;", TTxControl::Tx(tx)).Apply([session, tx](auto result) -> TStatus { if (!result.GetValue().IsSuccess()) { return result; } // parse result return session.ExecuteQuery("SELECT 2;", TTxControl::Tx(result.GetValue().GetTransaction()).CommitTx()).Apply([](auto result) -> TStatus { if (!result.GetValue().IsSuccess()) { return result; } // parse result }); }); }); //////////////////////////////////////////////////////// auto status = asyncStatus.GetValueSync(); if (!status.IsSuccess()) { std::cerr << ToString(status); }Новый асинхронный клиент
TDriver driver{"grpc://localhost:2136/local"}; TQueryClient client{driver}; auto asyncStatus = client.BeginTransaction().Apply([](auto result) { auto tx = result.GetValue().GetTransaction(); return tx.ExecuteQuery("SELECT 1;").Apply([session, tx](auto result) -> TStatus { if (!result.GetValue().IsSuccess()) { return result; } // parse result return tx.ExecuteQuery("SELECT 2;", {}, TExecuteQueryInTxSettings().Commit()).Apply([](auto result) -> TStatus { if (!result.GetValue().IsSuccess()) { return result; } // parse result }); }); }); //////////////////////////////////////////////////////// auto status = asyncStatus.GetValueSync(); if (!status.IsSuccess()) { std::cerr << ToString(status); }{% endlist %}
Ретрай интерактивной транзакции
Для ретрая транзакции используется метод
RetryTransaction(). В нем пользователю передается в использование сразуTTransaction. В настройках можно выставить режим неявного начала транзакции. Тогда в первом запросеExecuteQuery()будет переданTTxControl::BeginTx().{% list tabs %}
Старый клиент
TDriver driver{"grpc://localhost:2136/?database=local"}; TQueryClient client{driver}; auto status = client.RetryQuery([](TSession session) { auto result1 = session.ExecuteQuery("SELECT 1;", TTxControl::BeginTx()).GetValueSync(); if (!result1.IsSuccess()) { std::cerr << ToString(result1); return result1; } // parse result auto result2 = session.ExecuteQuery("SELECT 2;", TTxControl::Tx(result.GetTransaction()).CommitTx()).GetValueSync(); if (!result2.IsSuccess()) { std::cerr << ToString(result2); return result2; } // parse result }).GetValueSync(); if (!status.IsSuccess()) { std::cerr << ToString(status); }Новый синхронный клиент
TDriver driver{"grpc://localhost:2136/local"}; TQueryClient client{driver}; try { client.RetryTransaction([](TTransaction& tx) { auto result1 = tx.ExecuteQuery("SELECT 1;"); // parse result auto result2 = tx.ExecuteQuery("SELECT 2;"); // parse result }); } catch (NYdb::TDbRequestError& e) { std::cerr << e; }{% endlist %}
Асинхронный ретрай интерактивной транзакции
Для ретрая транзакции используется метод
RetryTransaction(). В нем пользователю передается в использование сразуTTransaction. В настройках можно выставить режим неявного начала транзакции. Тогда в первом запросеExecuteQuery()будет переданTTxControl::BeginTx().{% list tabs %}
Старый клиент
TDriver driver{"grpc://localhost:2136/?database=local"}; TQueryClient client{driver}; auto asyncStatus = client.RetryQuery([](TSession session) { return session.ExecuteQuery("SELECT 1;", TTxControl::BeginTx()).Apply([session](auto result) -> TStatus { if (!result.GetValue().IsSuccess()) { return result; } // parse result return session.ExecuteQuery("SELECT 2;", TTxControl::Tx(result.GetValue().GetTransaction()).CommitTx()).Apply([](auto result) -> TStatus { if (!result.GetValue().IsSuccess()) { return result; } // parse result }); }); }); //////////////////////////////////////////////////////// auto status = asyncStatus.GetValueSync(); if (!status.IsSuccess()) { std::cerr << ToString(status); }Новый асинхронный клиент
TDriver driver{"grpc://localhost:2136/local"}; TQueryClient client{driver}; auto asyncStatus = client.RetryTransaction([](TTransaction tx) -> TStatus { return tx.ExecuteQuery("SELECT 1;").Apply([tx](auto result) -> TStatus { if (!result.GetValue().IsSuccess()) { return result; } // parse result return tx.ExecuteQuery("SELECT 2;", {}, TExecuteQueryInTxSettings().Commit()).Apply([](auto result) -> TStatus { if (!result.GetValue().IsSuccess()) { return result; } // parse result }); }); }); //////////////////////////////////////////////////////// auto status = asyncStatus.GetValueSync(); if (!status.IsSuccess()) { std::cerr << ToString(status); }{% endlist %}
Beta Was this translation helpful? Give feedback.
All reactions