Skip to main content
Version: 0.0.3

FAQ

Why is aerospike-py written in Rust?

aerospike-py wraps the Aerospike Rust Client using PyO3 bindings, which gives several advantages over a pure-Python or C-extension approach:

  • Performance -- Rust compiles to native code. Benchmarks show throughput on par with (or better than) the official C-based client, especially for batch and async workloads.
  • Memory safety -- Rust's ownership model eliminates whole classes of bugs (use-after-free, buffer overflows, data races) without a garbage collector.
  • Native async -- The underlying client is built on Tokio, a production-grade async runtime. This makes the AsyncClient a first-class citizen rather than an afterthought.
  • Zero Python dependencies -- The base install (pip install aerospike-py) has no external Python dependencies. NumPy and OpenTelemetry are optional extras.

How does GIL handling work?

aerospike-py releases the Python Global Interpreter Lock (GIL) during all database I/O so that other Python threads can make progress while a request is in flight.

ClientMechanism
Sync Clientpy.detach() releases the GIL, then RUNTIME.block_on() runs the async Rust operation on the internal Tokio runtime. The GIL is re-acquired when the result is returned.
Async AsyncClientfuture_into_py() returns a Python awaitable. The actual work runs on the Tokio runtime without holding the GIL. When the future completes, Python::attach() re-acquires the GIL to hand the result back.

In both cases, the GIL is not held while the request travels to the Aerospike cluster, which means Python threads (or other async tasks) are free to run concurrently.

Is aerospike-py thread-safe?

Yes. A single Client instance can be shared safely across multiple threads. Internally the Rust client manages a connection pool, and all shared state is protected by lock-free or mutex-guarded structures.

import threading
import aerospike_py

client = aerospike_py.client({"hosts": [("127.0.0.1", 18710)]}).connect() # port varies by deployment

def worker(thread_id: int) -> None:
key = ("test", "demo", f"thread_{thread_id}")
client.put(key, {"tid": thread_id})
record = client.get(key)
assert record.bins["tid"] == thread_id

threads = [threading.Thread(target=worker, args=(i,)) for i in range(8)]
for t in threads:
t.start()
for t in threads:
t.join()
client.close()

Does it support Python free-threaded mode (3.14t)?

Yes. aerospike-py builds and runs on the experimental free-threaded CPython (PEP 703). CI runs unit tests and concurrency stress tests on Python 3.14t to verify correctness without the GIL.

Because the core logic lives in Rust -- which has its own memory safety guarantees -- the library is inherently safe even when the GIL is removed entirely.

Is NumPy required?

No. NumPy is an optional dependency.

# Base install -- no NumPy needed
pip install aerospike-py

# With NumPy support
pip install aerospike-py[numpy]

When NumPy is installed, you gain access to batch_read(..., _dtype=...) which returns a NumpyBatchRecords object containing results as a NumPy structured array, and batch_write_numpy() for bulk writes from structured arrays. All other functionality works identically without NumPy.

Can I migrate from the official C client?

Yes. aerospike-py is designed as a near-drop-in replacement. The import alias pattern makes the transition straightforward:

# Before
import aerospike

# After
import aerospike_py as aerospike

Most API signatures, constants, exception classes, and policy dicts are compatible. See the Migration Guide for a step-by-step walkthrough and the API Comparison for a detailed side-by-side table.

How do I enable OpenTelemetry tracing?

Tracing support is compiled into every build. To enable it:

pip install aerospike-py[otel]   # adds opentelemetry-api for context propagation
import aerospike_py

# Initialize before creating the client
aerospike_py.init_tracing()

client = aerospike_py.client({"hosts": [("127.0.0.1", 18710)]}).connect() # port varies by deployment
# ... all operations are traced automatically ...
client.close()

# Flush pending spans before exit
aerospike_py.shutdown_tracing()

Spans are exported via OTLP gRPC (default endpoint http://localhost:4317). Configure with standard OTEL_* environment variables. See the Tracing guide for details.

How do I enable Prometheus metrics?

aerospike-py ships a built-in Prometheus metrics HTTP server:

import aerospike_py

# Start metrics server on port 9464
aerospike_py.start_metrics_server(9464)

client = aerospike_py.client({"hosts": [("127.0.0.1", 18710)]}).connect() # port varies by deployment
# ... operations are metered automatically ...
client.close()

aerospike_py.stop_metrics_server()

Scrape http://localhost:9464/metrics from Prometheus. Operation latency histograms are recorded per operation type. See the Metrics guide for details.

What Aerospike server versions are supported?

aerospike-py is tested against Aerospike Server 6.x and 7.x (Community and Enterprise). It is built on the Aerospike Rust Client v2.0.0-alpha.9.

How do I report a bug or request a feature?

Open an issue on the GitHub repository:

Please include your Python version, OS, aerospike-py version (aerospike_py.__version__), and a minimal reproduction when reporting bugs.