Skip to content

Consumer Guide

Consumers receive messages from Danube topics via subscriptions. This guide covers creating consumers, the message loop, acknowledgment, and negative acknowledgment.

Create a consumer
use danube_client::{DanubeClient, SubType};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = DanubeClient::builder()
.service_url("http://127.0.0.1:6650")
.build()
.await?;
let mut consumer = client
.new_consumer()
.with_topic("/default/my-topic")
.with_consumer_name("my-consumer")
.with_subscription("my-subscription")
.with_subscription_type(SubType::Exclusive)
.build()?;
consumer.subscribe().await?;
Ok(())
}
  • Consumer Name: unique identifier for this consumer instance
  • Subscription: logical grouping of consumers (multiple consumers can share a subscription)
  • Subscription Type: controls message distribution. See Subscriptions

Message loop
consumer.subscribe().await?;
let mut stream = consumer.receive().await?;
while let Some(message) = stream.recv().await {
let payload = String::from_utf8_lossy(&message.payload);
println!("Received: {}", payload);
consumer.ack(&message).await?;
}

Each message exposes payload, attributes, and metadata:

Message fields
while let Some(message) = stream.recv().await {
let payload = String::from_utf8_lossy(&message.payload);
println!("Payload: {}", payload);
if let Some(attributes) = &message.attributes {
for (key, value) in attributes {
println!(" {}: {}", key, value);
}
}
consumer.ack(&message).await?;
}

When a consumer cannot process a message, it can reject it with nack(). The broker schedules redelivery based on the subscription’s failure policy.

NACK with retry
while let Some(message) = stream.recv().await {
match process(&message) {
Ok(_) => consumer.ack(&message).await?,
Err(e) => {
consumer.nack(
&message,
Some(1000), // retry after 1s minimum
Some(format!("processing failed: {}", e)),
).await?;
}
}
}

Parameters:

  • delay_ms (optional): minimum delay before redelivery. The broker uses the larger of this value and the subscription’s configured backoff delay
  • reason (optional): human-readable failure reason, attached to metrics and dead-letter metadata

What happens after NACK: the broker applies the subscription’s failure policy. If delivery attempts remain, the message is redelivered after the backoff delay. If max_redelivery_count is exceeded, the poison policy (dead_letter, drop, or block) takes effect. See Dispatch Strategies.


When a topic has partitions, consumers automatically receive from all partitions. Use the parent topic name:

Partitioned consumer
// Topic has 3 partitions: my-topic-part-0, my-topic-part-1, my-topic-part-2
let mut consumer = client
.new_consumer()
.with_topic("/default/my-topic") // Parent topic name
.with_consumer_name("partition-consumer")
.with_subscription("partition-sub")
.with_subscription_type(SubType::Exclusive)
.build()?;
consumer.subscribe().await?;
// Automatically receives from all 3 partitions
let mut stream = consumer.receive().await?;
while let Some(message) = stream.recv().await {
consumer.ack(&message).await?;
}
  • Client discovers all partitions automatically
  • Messages from all partitions are merged into a single stream
  • Ordering is preserved per-partition, not cross-partition

TypeConsumersOrderingUse Case
Exclusive1GuaranteedSequential workflows
SharedN (round-robin)NoneParallel processing
Failover1 active + standbyGuaranteedHA with ordering
Key-SharedN (by routing key)Per-keyPer-entity processing

For Key-Shared details (routing keys, key filtering, glob patterns), see Subscriptions.