kafrust 0.2.14

A pure Rust Kafka client with no librdkafka or C client binding dependency.
Documentation
mod common;

use std::io::{self, Write};

use kafrust::{AdminClient, ClientConfig, ClientMetrics, ConsumerGroupOffsetQuery, Error};

#[tokio::main]
async fn main() -> kafrust::Result<()> {
    common::init_request_gate(9)?;

    let bootstrap_servers = common::bootstrap_servers_from_env();
    let group_id = std::env::var("KAFRUST_GROUP_ID").unwrap_or_else(|_| "kafrust-smoke".to_owned());
    let topic = std::env::var("KAFRUST_TOPIC").unwrap_or_else(|_| "kafrust-smoke".to_owned());
    let partition = std::env::var("KAFRUST_PARTITION")
        .ok()
        .map(|value| {
            value
                .parse()
                .map_err(|_| Error::Unsupported("KAFRUST_PARTITION must be a partition index"))
        })
        .transpose()?
        .unwrap_or(0);

    let discovery_config = common::apply_security(
        ClientConfig::new(bootstrap_servers.clone())
            .client_id("kafrust-admin-group-offsets-failover-discovery"),
    )?;
    let mut bootstrap = discovery_config.clone().connect().await?;
    let coordinator = bootstrap.find_group_coordinator(group_id.clone()).await?;
    if coordinator.error_code != 0 {
        return Err(Error::Broker {
            code: coordinator.error_code,
            context: format!("find consumer group coordinator for {group_id}"),
        });
    }
    println!("group coordinator node {}", coordinator.node_id);
    io::stdout().flush().map_err(Error::Io)?;

    let metrics = ClientMetrics::new();
    let config = common::apply_security(
        ClientConfig::new(bootstrap_servers)
            .client_id("kafrust-admin-group-offsets-failover")
            .metrics(metrics.clone()),
    )?;
    let admin = AdminClient::new(config);
    let query = [ConsumerGroupOffsetQuery::new(topic.clone(), [partition])];
    let result = admin
        .list_consumer_group_offsets(&group_id, Some(&query))
        .await?;
    if result.error_code() != 0 {
        return Err(Error::Broker {
            code: result.error_code(),
            context: format!("list committed offsets for {group_id}"),
        });
    }
    let topic_result = result
        .topics()
        .iter()
        .find(|candidate| candidate.topic() == topic)
        .ok_or_else(|| Error::UnknownTopicOrPartition {
            topic: topic.clone(),
            partition,
        })?;
    let partition_result = topic_result
        .partitions()
        .iter()
        .find(|candidate| candidate.partition_index() == partition)
        .ok_or_else(|| Error::UnknownTopicOrPartition {
            topic: topic.clone(),
            partition,
        })?;
    if !partition_result.is_success() {
        return Err(Error::Broker {
            code: partition_result.error_code(),
            context: format!("list committed offset for {group_id}/{topic}-{partition}"),
        });
    }

    println!(
        "admin consumer group offsets failover completed {group_id}/{topic}-{partition} offset={} retries={}",
        partition_result.committed_offset(),
        metrics.snapshot().retries,
    );
    Ok(())
}