Source code for aerospike_sdk.sync.transactional_session

# Copyright 2025-2026 Aerospike, Inc.
#
# Portions may be licensed to Aerospike, Inc. under one or more contributor
# license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.

"""Synchronous multi-record transaction (MRT) session wrapper."""

from __future__ import annotations

import types
from typing import Optional, TYPE_CHECKING

from aerospike_async import AbortStatus, CommitStatus, Txn

from aerospike_sdk.aio.transactional_session import TransactionalSession as AsyncTransactionalSession
from aerospike_sdk.sync.client import _EventLoopManager
from aerospike_sdk.sync.session import SyncSession

if TYPE_CHECKING:
    from aerospike_sdk.policy.behavior import Behavior


[docs] class SyncTransactionalSession(SyncSession): """Sync context manager that groups operations into a multi-record transaction. Subclasses :class:`~aerospike_sdk.sync.session.SyncSession`, so every session API (``query``, ``upsert``, ``insert``, ``batch``, ...) works unchanged inside ``with``; the underlying async :class:`~aerospike_sdk.aio.transactional_session.TransactionalSession` threads the active :class:`~aerospike_async.Txn` onto every policy the builders hand to the PAC — the user never touches a policy. On clean exit the transaction is committed; if an exception propagates out of the block the transaction is aborted. Explicit :meth:`commit`, :meth:`abort`, and :meth:`rollback` (alias for ``abort``) are also available for manual control. Example: >>> with client.create_session().begin_transaction() as tx: ... tx.upsert(accounts.id("A")).bin("balance").set_to(100).execute() ... tx.upsert(accounts.id("B")).bin("balance").set_to(200).execute() # Auto-committed on clean exit; auto-aborted on exception. See Also: :meth:`aerospike_sdk.sync.session.SyncSession.begin_transaction` :meth:`aerospike_sdk.sync.cluster.Cluster.create_transactional_session` :class:`aerospike_sdk.aio.transactional_session.TransactionalSession` """
[docs] def __init__( self, async_txn_session: AsyncTransactionalSession, loop_manager: _EventLoopManager, ) -> None: """Wrap ``async_txn_session``; use :meth:`SyncSession.begin_transaction` instead. Args: async_txn_session: Underlying async :class:`~aerospike_sdk.aio.transactional_session.TransactionalSession` sharing the same client and behavior. loop_manager: Loop manager shared with the parent :class:`~aerospike_sdk.sync.client.SyncClient`. Note: Application code should not construct ``SyncTransactionalSession`` directly; call :meth:`SyncSession.begin_transaction` or :meth:`Cluster.create_transactional_session` instead. See Also: :meth:`aerospike_sdk.sync.session.SyncSession.begin_transaction` """ super().__init__(async_txn_session, loop_manager)
@property def _async_txn_session(self) -> AsyncTransactionalSession: # The underlying async session is always the transactional subtype # once this class wraps it. return self._async_session # type: ignore[return-value] @property def txn(self) -> Txn: """Return the underlying :class:`~aerospike_async.Txn`. Raises: RuntimeError: If the session has not been entered (no active txn). Returns: The active :class:`~aerospike_async.Txn`. """ return self._async_txn_session.txn @property def active(self) -> bool: """``True`` when a transaction has been started and not yet finalized. Returns: Whether a transaction is currently active on this session. """ return self._async_txn_session.active
[docs] def commit(self) -> CommitStatus: """Commit the transaction and return the server-reported status. Raises: RuntimeError: If the session has no active transaction. Returns: :class:`~aerospike_async.CommitStatus` reported by the server. See Also: :meth:`abort`: Undo the transaction instead of committing. """ return self._loop_manager.run_async(self._async_txn_session.commit())
[docs] def abort(self) -> AbortStatus: """Abort the transaction and return the server-reported status. Raises: RuntimeError: If the session has no active transaction. Returns: :class:`~aerospike_async.AbortStatus` reported by the server. See Also: :meth:`commit`: Persist the transaction instead of aborting. :meth:`rollback`: Alias for this method. """ return self._loop_manager.run_async(self._async_txn_session.abort())
[docs] def rollback(self) -> AbortStatus: """Alias for :meth:`abort`. Returns: :class:`~aerospike_async.AbortStatus` reported by the server. """ return self.abort()
def __enter__(self) -> "SyncTransactionalSession": self._loop_manager.run_async(self._async_txn_session.__aenter__()) return self def __exit__( self, exc_type: Optional[type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[types.TracebackType], ) -> None: self._loop_manager.run_async( self._async_txn_session.__aexit__(exc_type, exc_val, exc_tb) )