Behaviors and Selectors
For the complete documentation index see: llms.txt
All documentation pages available in markdown.
Behaviors control timeout, retry, and protocol settings per operation type. They replace the old per-policy model with a single, composable configuration.
Core concepts
Behavior— an immutable set of operational settingsSelectors— target which operation types a setting applies to (reads, writes, batches, etc.)Session— created from a cluster with a specific behavior; all operations on that session use those settings
Creating a session with a behavior
Cluster cluster = new ClusterDefinition("localhost", 3000).connect();
Session defaultSession = cluster.createSession(Behavior.DEFAULT);📖 API reference:
ClusterDefinition(String,int)|ClusterDefinition.connect()|Cluster.createSession(Behavior)
from aerospike_sdk import Behavior, ClusterDefinition
cluster = await ClusterDefinition("localhost", 3000).connect()
default_session = cluster.create_session(Behavior.DEFAULT)📖 API reference:
Behavior.DEFAULT
Deriving behaviors
All custom behaviors derive from an existing one — deriveWithChanges in Java, derive_with_changes in Python:
Behavior production = Behavior.DEFAULT.deriveWithChanges("production", builder -> builder .on(Selectors.all(), ops -> ops .abandonCallAfter(Duration.ofSeconds(5)) ));
Session productionSession = cluster.createSession(production);📖 API reference:
Cluster.createSession(Behavior)
from datetime import timedeltafrom aerospike_sdk import Behavior
production = Behavior.DEFAULT.derive_with_changes( "production", total_timeout=timedelta(seconds=5),)
production_session = cluster.create_session(production)📖 API reference:
Behavior.DEFAULT
Selectors reference
Selectors narrow which operations a setting applies to. Settings cascade from general to specific — more specific selectors override broader ones.
Entry points
| Selector | Targets |
|---|---|
Selectors.all() | Every operation |
Selectors.reads() | All read operations |
Selectors.writes() | All write operations |
Selectors.transaction() | Transaction verify/roll operations |
Narrowing reads
Selectors.reads() // all readsSelectors.reads().get() // single-key readsSelectors.reads().batch() // batch readsSelectors.reads().query() // dataset queries (scans, SI queries)📖 API reference:
com.aerospike.client.sdk
# Python has no Selectors.reads() / .get() / .batch() / .query() API. Configure reads# via flat kwargs on Behavior (e.g. total_timeout, replica, consistency_level,# max_concurrent_nodes, record_queue_size) for the whole session; you cannot target only# one read shape (single-key vs batch vs query) inside a single behavior.📖 API reference:
Behavior
Narrowing writes
Selectors.writes() // all writesSelectors.writes().retryable() // idempotent writes (safe to retry)Selectors.writes().nonRetryable() // non-idempotent writesSelectors.writes().retryable().point() // single-key retryable writesSelectors.writes().retryable().batch() // batch retryable writesSelectors.writes().nonRetryable().point() // single-key non-retryable writesSelectors.writes().nonRetryable().batch() // batch non-retryable writes📖 API reference:
com.aerospike.client.sdk
# No Selectors.writes() narrowing in Python (retryable vs point vs batch). Use one# behavior’s max_retries / retry_delay / commit_level for all writes on that session,# or split workloads across multiple behaviors if you need different write tuning.📖 API reference:
Behavior
Mode selection (AP vs CP)
Append .ap() or .cp() for mode-specific settings. Select mode last for best compile-time type safety:
// Recommended: mode last -> full type safetySelectors.reads().batch().ap() // exposes readMode()Selectors.writes().retryable().point().ap() // exposes commitLevel()
// Works but loses type-specific methods in IDESelectors.writes().ap().retryable().point() // commitLevel() not visible at compile time📖 API reference:
com.aerospike.client.sdk
from aerospike_sdk import Behavior
# Python has no .ap() / .cp() selector chain. Use predefined bases (e.g.# Behavior.DEFAULT, Behavior.READ_FAST, Behavior.FAST_RACK_AWARE) for AP-style setups,# and Behavior.STRICTLY_CONSISTENT for SC. Further tune with derive_with_changes(...)# and kwargs such as replica, consistency_level, and commit_level.📖 API reference:
Behavior.DEFAULT
Available settings
Common (available on all selectors)
| Setting | Description |
|---|---|
abandonCallAfter(Duration) | Total timeout for the entire operation (including retries) |
waitForCallToComplete(Duration) | Socket timeout per individual attempt |
waitForConnectionToComplete(Duration) | Connection establishment timeout |
waitForSocketResponseAfterCallFails(Duration) | How long to wait for a socket response after the call has already timed out |
maximumNumberOfCallAttempts(int) | Max retry attempts |
delayBetweenRetries(Duration) | Fixed delay between retry attempts |
replicaOrder(Replica) | Which replica to read/write first (SEQUENCE, MASTER, etc.) |
sendKey(boolean) | Whether to send the user key to the server |
useCompression(boolean) | Enable network compression |
Batch-specific
Available on .reads().batch(), .writes().*.batch(), and .transaction().*:
| Setting | Description |
|---|---|
maxConcurrentNodes(int) | Max parallel node connections for batch |
allowInlineMemoryAccess(boolean) | Allow batch sub-commands to run inline on memory-only namespaces |
allowInlineSsdAccess(boolean) | Allow batch sub-commands to run inline on SSD-backed namespaces |
Query-specific
Available on .reads().query() and .writes().*.query():
| Setting | Description |
|---|---|
recordQueueSize(int) | Client-side result buffer size |
Read-specific
| Setting | Selector | Description |
|---|---|---|
resetTtlOnReadAtPercent(int) | .reads() | Reset record TTL on read when remaining TTL drops below this percentage |
readMode(ReadModeAP) | .reads().ap() | AP read consistency (ONE, ALL) |
consistency(ReadModeSC) | .reads().cp() | SC read consistency (SESSION, LINEARIZE) |
Write-specific
| Setting | Selector | Description |
|---|---|---|
useDurableDelete(boolean) | .writes() | Use durable delete for tombstones |
simulateXdrWrite(boolean) | .writes() | Simulate XDR (cross-datacenter replication) write |
commitLevel(CommitLevel) | .writes().*.ap() | AP write durability (COMMIT_ALL, COMMIT_MASTER) |
Transaction operations
Behavior custom = Behavior.DEFAULT.deriveWithChanges("custom", builder -> builder .on(Selectors.transaction().txnVerify(), ops -> ops .maximumNumberOfCallAttempts(10) ) .on(Selectors.transaction().txnRoll(), ops -> ops .delayBetweenRetries(Duration.ofSeconds(1)) ));📖 API reference:
com.aerospike.client.sdk
from datetime import timedeltafrom aerospike_sdk import Behavior
# No per-operation txn_verify / txn_roll selectors in Python; retry settings apply to# the whole behavior. Split sessions only if you need different globals for verify vs roll.custom = Behavior.DEFAULT.derive_with_changes( "custom", max_retries=10, retry_delay=timedelta(seconds=1),)📖 API reference:
Behavior.DEFAULT
How resolution works
Settings resolve through two independent dimensions: selector cascade within a single behavior, and inheritance across derived behaviors.
Dimension 1: Selector cascade
Each .on(selector, ...) call adds a patch. When the SDK needs settings for a specific operation, it applies all matching patches in order. More specific selectors override broader ones:
all() -> reads() -> reads().batch() -> reads().batch().ap() ^ writes() -> writes().retryable() -> writes().retryable().point()Within a single behavior, this is last-writer wins — if two patches match the same operation, the more specific one takes precedence.
Behavior tiered = Behavior.DEFAULT.deriveWithChanges("tiered", builder -> builder .on(Selectors.all(), ops -> ops .abandonCallAfter(Duration.ofSeconds(2)) ) .on(Selectors.reads(), ops -> ops .abandonCallAfter(Duration.ofSeconds(1)) ) .on(Selectors.reads().batch(), ops -> ops .abandonCallAfter(Duration.ofSeconds(5)) ));📖 API reference:
com.aerospike.client.sdk
Resolution for a batch read: all() sets 2s, reads() narrows to 1s, reads().batch() narrows to 5s.
Resolution for a single-key read: all() sets 2s, reads() narrows to 1s. The reads().batch() patch doesn’t match.
Resolution for a write: only all() matches -> 2s.
from datetime import timedeltafrom aerospike_sdk import Behavior
# Python has no per-selector cascade. Model different operation timeouts# with separate behaviors, one per workload.tiered_writes = Behavior.DEFAULT.derive_with_changes( "tiered_writes", total_timeout=timedelta(seconds=2))tiered_reads = Behavior.DEFAULT.derive_with_changes( "tiered_reads", total_timeout=timedelta(seconds=1))tiered_batch_reads = Behavior.DEFAULT.derive_with_changes( "tiered_batch_reads", total_timeout=timedelta(seconds=5))
# Create a session per workloadwrites_session = cluster.create_session(tiered_writes)reads_session = cluster.create_session(tiered_reads)batch_reads_session = cluster.create_session(tiered_batch_reads)📖 API reference:
Behavior.DEFAULT
Dimension 2: Behavior inheritance
A derived behavior starts with the fully resolved settings from its parent, then applies its own patches on top. This forms a tree:
DEFAULT (all: 1s, 3 retries) / \ v v production reporting (all: 5s, 3 retries) (all: 30s) | v highLoad (all: 5s, 3 retries) (batch reads: 16 concurrent nodes)Behavior production = Behavior.DEFAULT.deriveWithChanges("production", builder -> builder .on(Selectors.all(), ops -> ops .abandonCallAfter(Duration.ofSeconds(5)) .maximumNumberOfCallAttempts(3) ));
Behavior highLoad = production.deriveWithChanges("highLoad", builder -> builder .on(Selectors.reads().batch(), ops -> ops .maxConcurrentNodes(16) ));📖 API reference:
com.aerospike.client.sdk
from datetime import timedeltafrom aerospike_sdk import Behavior
production = Behavior.DEFAULT.derive_with_changes( "production", total_timeout=timedelta(seconds=5), max_retries=3,)
high_load = production.derive_with_changes( "high_load", max_concurrent_nodes=16,)📖 API reference:
Behavior.DEFAULT
Resolution for a batch read on highLoad:
| Step | Source | What happens |
|---|---|---|
| 1 | DEFAULT resolves | all() -> 1s timeout, 3 retries |
| 2 | production patches applied | all() overrides -> 5s timeout, 3 retries |
| 3 | highLoad patches applied | reads().batch() adds -> 16 concurrent nodes |
| Result | 5s timeout, 3 retries, 16 concurrent nodes |
A child’s patches can override anything from the parent — parent settings are a starting point, not a floor.
Both dimensions combined
The two dimensions compose naturally. Within each behavior in the chain, selector patches cascade from general to specific. Across behaviors, the child’s resolved matrix starts from the parent’s fully resolved matrix.
Behavior base = Behavior.DEFAULT.deriveWithChanges("base", builder -> builder .on(Selectors.all(), ops -> ops .abandonCallAfter(Duration.ofSeconds(5)) ) .on(Selectors.reads(), ops -> ops .abandonCallAfter(Duration.ofSeconds(2)) ));
Behavior child = base.deriveWithChanges("child", builder -> builder .on(Selectors.reads().batch(), ops -> ops .abandonCallAfter(Duration.ofSeconds(10)) ));📖 API reference:
com.aerospike.client.sdk
Resolution for a batch read on child:
| Step | Source | Timeout |
|---|---|---|
| 1 | base: all() | 5s |
| 2 | base: reads() overrides | 2s |
| 3 | base resolved for batch read | 2s (parent done) |
| 4 | child: reads().batch() overrides | 10s (final) |
Resolution for a single-key read on child: inherits 2s from base (no child patch matches) -> 2s.
Resolution for a write on child: inherits 5s from base’s all() -> 5s.
Multiple sessions, one cluster
Behavior reporting = Behavior.DEFAULT.deriveWithChanges("reporting", builder -> builder .on(Selectors.all(), ops -> ops .abandonCallAfter(Duration.ofSeconds(30)) ));
Session defaultSession = cluster.createSession(Behavior.DEFAULT);Session reportingSession = cluster.createSession(reporting);📖 API reference:
Cluster.createSession(Behavior)
from datetime import timedeltafrom aerospike_sdk import Behavior
reporting = Behavior.DEFAULT.derive_with_changes( "reporting", total_timeout=timedelta(seconds=30),)
default_session = cluster.create_session(Behavior.DEFAULT)reporting_session = cluster.create_session(reporting)📖 API reference:
Behavior.DEFAULT
Both sessions share the same cluster connection pool but have different operational settings.