use bytes::Bytes;
use kafka_client::{Client, ConsumerConfig, ProducerConfig, ProducerRecord, admin::NewTopic};
use std::time::Duration;
fn get_bootstrap_addrs() -> Vec<String> {
let bootstrap =
std::env::var("KAFKA_BOOTSTRAP").unwrap_or_else(|_| "127.0.0.1:9092".to_string());
bootstrap.split(',').map(|s| s.trim().to_string()).collect()
}
fn get_topic_name() -> String {
std::env::var("KAFKA_TOPIC").unwrap_or_else(|_| "tc-large".to_string())
}
fn get_message_count() -> i32 {
std::env::var("KAFKA_MESSAGE_COUNT")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(100)
}
#[tokio::main]
async fn main() {
let _ = tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.try_init();
let addrs = get_bootstrap_addrs();
let topic = get_topic_name();
let msg_count = get_message_count();
println!("=== Large Batch Example ===");
println!("Bootstrap: {:?}", addrs);
println!("Topic: {}", topic);
println!("Message count: {}", msg_count);
println!("\n[1] Connecting to Kafka...");
let client = match Client::builder(addrs)
.with_client_id("large-batch-example")
.with_metadata_ttl(Duration::from_secs(10))
.build()
.await
{
Ok(c) => c,
Err(e) => {
eprintln!("ERROR: Failed to connect: {}", e);
std::process::exit(1);
}
};
println!("Connected successfully!");
println!("\n[2] Creating topic '{}' (3 partitions)...", topic);
let cluster_info = client.admin().describe_cluster().await.unwrap();
let rf = (3).min(cluster_info.brokers.len()).max(1) as i16;
let result = client
.admin()
.create_topic(&NewTopic::new(&topic, 3, rf))
.await
.unwrap();
use kafka_client::KafkaErrorCode;
if !result.error_code.is_ok() && result.error_code != KafkaErrorCode::TOPIC_ALREADY_EXISTS {
eprintln!("ERROR: Topic creation failed: {}", result.error_code);
std::process::exit(1);
}
println!(" Topic '{}' ready ({})", topic, result.error_code);
tokio::time::sleep(Duration::from_secs(2)).await;
client
.refresh_metadata()
.await
.expect("Failed to refresh metadata");
println!("\n[3] Producing {} messages to '{}'...", msg_count, topic);
let producer_config = ProducerConfig::new().with_retries(5);
let producer = client.producer(producer_config).await;
let records: Vec<ProducerRecord> = (0..msg_count)
.map(|i| ProducerRecord::new(&topic, Bytes::from(format!("msg-{}", i))))
.collect();
let sent = producer
.send_batch(records)
.await
.expect("Failed to buffer batch");
if sent as i32 != msg_count {
eprintln!(
"ERROR: send_batch returned {}, expected {}",
sent, msg_count
);
std::process::exit(1);
}
producer.flush().await.expect("Failed to flush producer");
println!(" Produced {} messages", msg_count);
println!("\n[4] Consuming messages...");
let consumer_config = ConsumerConfig::new()
.with_group_id("cg-large-example")
.with_auto_commit_interval(Duration::from_secs(1))
.with_earliest()
.with_min_bytes(0)
.with_max_bytes(1048576)
.with_max_wait(Duration::from_secs(5));
let mut consumer = client.consumer(consumer_config);
match consumer.subscribe(vec![topic.clone()]).await {
Ok(_) => println!(" Subscribed to '{}'", topic),
Err(e) => {
eprintln!("ERROR: Failed to subscribe: {}", e);
std::process::exit(1);
}
}
let mut all_records = Vec::new();
let deadline = std::time::Instant::now() + Duration::from_secs(60);
while all_records.len() < msg_count as usize && std::time::Instant::now() < deadline {
match consumer.poll_timeout(Duration::from_millis(3000)).await {
Ok(records) => {
for r in &records {
println!(
" Received: partition={}, offset={}, value={}",
r.partition,
r.offset,
String::from_utf8_lossy(&r.value)
);
}
all_records.extend(records);
}
Err(e) => eprintln!(" WARNING: Poll error: {}", e),
}
}
println!(
"\n[5] Result: consumed {} / {} messages",
all_records.len(),
msg_count
);
if all_records.len() as i32 >= msg_count {
println!("SUCCESS: All messages consumed!");
} else {
eprintln!(
"FAILURE: Expected at least {}, got {}",
msg_count,
all_records.len()
);
}
println!("\n[6] Shutting down...");
if let Err(e) = consumer.close().await {
eprintln!("WARNING: Consumer close error: {}", e);
}
if let Err(e) = client.close().await {
eprintln!("WARNING: Client close error: {}", e);
}
println!("Done.");
}