use std::sync::Arc;
use nodedb_types::sync::wire::{AckStatus, EngineKind, KvPushAckMsg, SyncFrame, stream_id_for};
use crate::sync::client::SyncClient;
use crate::sync::delegate::SyncDelegate;
pub(super) async fn handle_kv_push_ack(
client: &Arc<SyncClient>,
delegate: &Arc<dyn SyncDelegate>,
frame: &SyncFrame,
) {
let Some(ack) = frame.decode_body::<KvPushAckMsg>() else {
tracing::warn!(
frame_len = frame.body.len(),
"KvPushAck frame body failed to decode; the write stays in flight until reconnect"
);
return;
};
apply_kv_push_ack(client, delegate, &ack).await;
}
pub(super) async fn apply_kv_push_ack(
client: &Arc<SyncClient>,
delegate: &Arc<dyn SyncDelegate>,
ack: &KvPushAckMsg,
) {
tracing::debug!(
collection = %ack.collection,
batch_id = ack.batch_id,
status = ?ack.status,
"KvPushAck received from Origin"
);
match &ack.status {
AckStatus::Applied | AckStatus::Duplicate => {
let stream_id = stream_id_for(EngineKind::Kv, &ack.collection);
delegate.record_stream_ack(stream_id, ack.applied_seq).await;
retire(delegate, ack).await;
}
AckStatus::Accepted => {
}
AckStatus::Fenced => {
tracing::error!(
collection = %ack.collection,
batch_id = ack.batch_id,
"KvPushAck: producer fenced by Origin; halting push"
);
client.set_fenced();
}
AckStatus::Gap { expected } => {
tracing::warn!(
collection = %ack.collection,
batch_id = ack.batch_id,
expected,
applied_seq = ack.applied_seq,
"KvPushAck: sequence gap detected by Origin; re-sending un-acked writes"
);
delegate.clear_engine_in_flight().await;
}
AckStatus::Rejected { reason } => {
tracing::error!(
collection = %ack.collection,
key = %String::from_utf8_lossy(&ack.key),
batch_id = ack.batch_id,
reason = %reason,
"KvPushAck: Origin permanently rejected this KV write; \
retiring it — Origin does not hold this write and it will not retry"
);
retire(delegate, ack).await;
}
}
}
async fn retire(delegate: &Arc<dyn SyncDelegate>, ack: &KvPushAckMsg) {
if let Err(e) = delegate.retire_kv_write(ack.batch_id).await {
tracing::error!(
collection = %ack.collection,
batch_id = ack.batch_id,
error = %e,
"KvPushAck: retiring the acknowledged write failed; it is re-sent on reconnect"
);
}
}