use crate::error::LaserError;
use iggy::prelude::*;
use tokio::time::{Duration, sleep};
pub(crate) const MAX_DRAIN_MESSAGES: usize = 10_000;
pub(crate) const MAX_TOPIC_PARTITIONS: u32 = 1024;
pub(crate) fn bounded_partitions(reported: u32) -> u32 {
reported.min(MAX_TOPIC_PARTITIONS)
}
pub(crate) struct PartitionBatch {
pub messages: Vec<IggyMessage>,
pub next_offset: u64,
}
#[cfg(feature = "agent")]
pub(crate) async fn tail_anchored_offset(
client: &IggyClient,
stream: &Identifier,
topic: &Identifier,
consumer: &Consumer,
partition: u32,
from_offset: u64,
) -> Result<u64, LaserError> {
let polled = client
.poll_messages(
stream,
topic,
Some(partition),
consumer,
&PollingStrategy::last(),
1,
false,
)
.await?;
let Some(last) = polled.messages.last() else {
return Ok(from_offset);
};
let window_start = last
.header
.offset
.saturating_sub(MAX_DRAIN_MESSAGES as u64 - 1);
Ok(from_offset.max(window_start))
}
pub(crate) async fn drain_partition(
client: &IggyClient,
stream: &Identifier,
topic: &Identifier,
consumer: &Consumer,
partition: u32,
from_offset: u64,
batch: u32,
) -> Result<PartitionBatch, LaserError> {
let mut offset = from_offset;
let mut messages = Vec::new();
loop {
let mut last_error = None;
let mut polled = None;
for attempt in 0..5 {
match client
.poll_messages(
stream,
topic,
Some(partition),
consumer,
&PollingStrategy::offset(offset),
batch,
false,
)
.await
{
Ok(batch) => {
polled = Some(batch);
break;
}
Err(error) if crate::laser::is_transient_iggy_io_error(&error) && attempt < 4 => {
last_error = Some(error);
sleep(Duration::from_millis(50 * (attempt + 1))).await;
}
Err(error) => return Err(error.into()),
}
}
let polled = polled
.ok_or_else(|| LaserError::from(last_error.expect("retry loop stores the error")))?;
let Some(last) = polled.messages.last() else {
break;
};
offset = last.header.offset.saturating_add(1);
let count = polled.messages.len();
messages.extend(polled.messages);
if (count as u32) < batch {
break;
}
if messages.len() >= MAX_DRAIN_MESSAGES {
break;
}
}
Ok(PartitionBatch {
messages,
next_offset: offset,
})
}