Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Choosing Delivery Semantics

Selecting the appropriate delivery semantic involves balancing reliability requirements against performance and complexity costs. This document provides a decision framework for choosing between at-most-once, at-least-once, and exactly-once semantics.


Evaluate data criticalityData loss acceptable?yesnoHigh throughput priority?yesnoTelemetryLogsMetricsAt-Most-OnceAt-Least-Once(simple config)Duplicates acceptable?yesnoMost productionworkloadsAt-Least-Once +Idempotent ConsumerKafka-to-Kafka only?yesnoKafka StreamsInternal pipelinesExactly-OnceExternal systemidempotent?yesnoAt-Least-Once +Idempotent SinkAdd dedup tableor outbox patternAt-Least-Once +Deduplication Layer
RequirementAt-Most-OnceAt-Least-OnceExactly-Once
No data loss (acks=all, ISR ok, unclean leader election disabled)
No duplicates
High throughput⚠️
Low latency⚠️
Simple implementation
Kafka-only
External systems⚠️

Legend: ✅ Supported | ⚠️ With constraints | ❌ Not supported

Kafka exactly-once applies to Kafka clients and Kafka Streams transactions. End-to-end exactly-once with external systems still requires idempotent or transactional integration.


At-Most-Once SuitableTelemetryLoggingReal-time UpdatesIoT sensorsApplication metricsHealth checksApplication logsAccess logsDebug tracesGame stateLocation trackingPrice feedsHigh volumeIndividual loss acceptableAggregates matterStale data worsethan missing data
Use CaseWhy At-Most-Once
IoT telemetryHigh-volume; individual readings expendable
Application metricsAggregate accuracy tolerates occasional loss
Real-time gamingNext update arrives quickly
Log streamingMissing lines rarely block debugging
At-Least-Once SuitableBusiness EventsData PipelinesNotificationsOrder placedUser registeredPayment initiatedETL processesData warehousingAnalytics ingestionEmail triggersPush notificationsWebhook deliveryCannot lose eventsDuplicates handledby idempotent design
Use CaseWhy At-Least-OnceDuplicate Handling
Order processingOrders must not be lostOrder ID deduplication
User eventsUser actions must be capturedEvent ID + timestamp
Financial transactionsMoney movement must be recordedTransaction ID
Email notificationsUsers must receive communicationsEmail dedup by user+type
Exactly-Once RequiredStream ProcessingFinancial CalculationsBilling/MeteringKafka Streams aggregationsStateful transformationsWindow computationsBalance computationsPortfolio valuationRisk calculationsUsage countingAPI call meteringResource consumptionAggregates must beexactly correctDuplicate transactionsincorrect balances
Use CaseWhy Exactly-OnceAlternative
Kafka Streams aggregatesSUM/COUNT must be exactNone (use EOS)
Balance calculationsDuplicate credits/debits cause errorsStrong idempotency
Usage meteringBilling must be accurateDedup with strong guarantees
Vote countingEach vote counted onceDedup table with unique constraint

Data TypeTypical SemanticRationale
Metrics/telemetryAt-most-onceVolume, expendability
LogsAt-most-onceVolume, non-critical
User activityAt-least-onceCannot lose, naturally deduped
Business transactionsAt-least-onceCritical, idempotent design
Financial recordsExactly-once or strong at-least-onceAccuracy critical
Aggregated stateExactly-onceCorrectness required
Data Criticality SpectrumLow CriticalityMedium CriticalityHigh CriticalityDebug logsHeartbeatsCache warmersAnalytics eventsUser clicksSearch queriesOrdersPaymentsAudit logsAt-Most-Onceto At-Least-OnceAt-Least-Onceto Exactly-Once

SemanticLatency OverheadThroughput ImpactResource Usage
At-most-onceBaselineBaselineLow
At-least-once+2-10ms (workload-dependent)85-95% (workload-dependent)Medium
Exactly-once+10-50ms (workload-dependent)50-80% (workload-dependent)High

Actual performance impact depends on batching, compression, replication, and disk/network latency.

Implementation ComplexityAt-Most-OnceAt-Least-OnceExactly-OnceProducer: acks=0Consumer: commit firstMonitoring: basicProducer: acks=all, retriesConsumer: process firstDedup: idempotent designMonitoring: duplicatesProducer: transactionalConsumer: read_committedCoordination: complexError handling: extensiveMonitoring: transactions
AspectAt-Most-OnceAt-Least-OnceExactly-Once
Code complexitySimpleModerateComplex
Testing effortLowMediumHigh
Debugging difficultyEasyModerateChallenging
Operational overheadLowMediumHigh
SemanticDevelopmentOperationsInfrastructure
At-most-onceLowLowLow
At-least-onceMediumMediumMedium
Exactly-onceHighHighHigh

At-Most-OnceAt-Least-OnceExactly-Onceacks=0retries=0acks=allretries=MAXidempotent consumertransactional.idread_committedEnable acks, retriesEnable transactions

Producer changes:

# Before
acks=0
retries=0
# After
acks=all
retries=2147483647
enable.idempotence=true

Consumer changes:

// Before: commit first
consumer.poll(timeout);
consumer.commitSync();
for (record : records) process(record);
// After: process first
consumer.poll(timeout);
for (record : records) process(record);
consumer.commitSync();

Additional requirements:

  • Implement idempotent consumer logic
  • Add message ID tracking or natural idempotence
  • Idempotence requires acks=all and max.in.flight.requests.per.connection<=5

Producer changes:

# Before
acks=all
enable.idempotence=true
# After
acks=all
enable.idempotence=true
transactional.id=my-app-instance-1

Consumer changes:

# Before
enable.auto.commit=false
# After
enable.auto.commit=false
isolation.level=read_committed

Code changes:

// Before
for (record : records) {
process(record);
producer.send(output);
}
consumer.commitSync();
// After
producer.initTransactions();
producer.beginTransaction();
for (record : records) {
process(record);
producer.send(output);
}
producer.sendOffsetsToTransaction(offsets, consumer.groupMetadata());
producer.commitTransaction();

Different topics may require different semantics within the same application.

Multi-Semantic ApplicationTopicsApplicationmetrics-topic(at-most-once)orders-topic(at-least-once)payments-topic(exactly-once)acks=0acks=alltransactions
// Multiple producers with different configurations
Producer<String, String> metricsProducer = createProducer(acks=0);
Producer<String, String> ordersProducer = createProducer(acks=all);
Producer<String, String> paymentsProducer = createTransactionalProducer();
// Route by data type
switch (eventType) {
case METRIC:
metricsProducer.send(record); // Fire and forget
break;
case ORDER:
ordersProducer.send(record, callback); // With retry
break;
case PAYMENT:
paymentsProducer.beginTransaction();
paymentsProducer.send(record);
paymentsProducer.commitTransaction();
break;
}
Tiered ProcessingIngestion Layer(at-most-once)Processing Layer(at-least-once)Output Layer(exactly-once)High volumeQuick acceptanceValidationEnrichmentAggregationFinal statefiltertransform

Anti-Pattern: EOS for LogsApplication logsExactly-once pipelineHigh latencyComplex operationsHigh costLogs don't need EOSAt-most-once sufficientMassive cost/complexity overhead
Anti-Pattern: AMO for PaymentsPayment eventsAt-most-onceLost paymentsCustomer complaintsRevenue lossPayments require at-least-onceor exactly-onceData loss unacceptable
Anti-Pattern: Mixed ProducersSame TopicInconsistent reliabilityConfusing behaviorProducer A (acks=0)Producer B (acks=all)All producers to same topicshould use same semantics

  • What is the business impact of losing a message?
  • What is the business impact of processing duplicates?
  • What is the acceptable latency?
  • What is the required throughput?
  • Does the consumer have natural idempotence?
  • Are external systems involved?
  • What is the team’s operational capability?
If…Then use…
Loss acceptable, throughput criticalAt-most-once
Loss unacceptable, can handle duplicatesAt-least-once
Loss and duplicates unacceptable, Kafka-onlyExactly-once
Loss and duplicates unacceptable, external systemsAt-least-once + idempotent sink
  • Performance tested under expected load
  • Failure scenarios tested
  • Monitoring in place for semantic violations
  • Runbooks for common issues
  • Team trained on operational procedures

SemanticBest ForAvoid For
At-most-onceTelemetry, logs, real-time updatesTransactions, orders, critical events
At-least-onceMost business events, general purposeWhen duplicates cause financial impact
Exactly-onceAggregations, billing, financial calculationsLogs, metrics, non-critical data