Transactions use %Aerospike.Txn{} handles plus runtime tracking in the started cluster. Creating a handle does not start a transaction by itself; tracking is initialized when Aerospike.transaction/2 or Aerospike.transaction/3 enters the callback.

The current transaction surface is proved against the Enterprise profile and covers transaction-aware single-record commands. Do not use scans or queries inside a transaction callback.

Callback Transactions

The callback owns the lifecycle. The client commits when the callback returns successfully and aborts when it raises an Aerospike.Error, raises another exception, throws, or exits. A returned {:error, reason} tuple is still an ordinary callback return value, so raise when the transaction should abort.

key1 = Aerospike.key("test", "orders", "order:1")
key2 = Aerospike.key("test", "orders", "order:2")

{:ok, :written} =
  Aerospike.transaction(:aerospike, fn txn ->
    {:ok, _} =
      Aerospike.put(:aerospike, key1, %{"status" => "open"}, txn: txn)

    {:ok, _} =
      Aerospike.put(:aerospike, key2, %{"status" => "open"}, txn: txn)

    :written
  end)

The cluster argument must currently be the registered atom name because transaction tracking and supervisor lookups resolve from that name.

Explicit Handles

Create a handle with options when the caller needs to choose a transaction timeout.

txn = Aerospike.Txn.new(timeout: 5_000)

{:ok, result} =
  Aerospike.transaction(:aerospike, txn, fn tx ->
    {:ok, :open} = Aerospike.txn_status(:aerospike, tx)
    {:ok, _} = Aerospike.add(:aerospike, key1, %{"attempts" => 1}, txn: tx)
    :updated
  end)

result

A transaction handle is valid only against the cluster that initialized its tracking row. Reusing one handle concurrently or against another cluster is unsupported.

Manual Lifecycle Helpers

commit/2, abort/2, and txn_status/2 operate on an already-open tracked transaction. They do not initialize a fresh %Aerospike.Txn{} by themselves.

{:ok, :checked} =
  Aerospike.transaction(:aerospike, fn tx ->
    {:ok, :open} = Aerospike.txn_status(:aerospike, tx)
    :checked
  end)

Most callers should let transaction/2 or transaction/3 commit or abort the callback. Calling manual lifecycle helpers requires an initialized tracking row and should stay sequential.

After commit or abort, the runtime tracking row is cleaned up. A later txn_status/2 call can therefore return an error instead of a terminal state.