off by one issue

This commit is contained in:
phiresky 2024-04-15 21:05:14 +02:00
parent 5e986ef5dd
commit c1932f9009

View file

@ -75,7 +75,7 @@ impl InstanceWorker {
/// this worker only returns if (a) there is an internal error or (b) the cancellation token is cancelled (graceful exit) /// this worker only returns if (a) there is an internal error or (b) the cancellation token is cancelled (graceful exit)
async fn loop_until_stopped(&mut self) -> Result<()> { async fn loop_until_stopped(&mut self) -> Result<()> {
self.initial_fail_sleep().await?; self.initial_fail_sleep().await?;
let mut latest_id = self.get_latest_id().await?; let (mut last_sent_id, mut newest_id) = self.get_latest_ids().await?;
// activities that have been successfully sent but // activities that have been successfully sent but
// that are not the lowest number and thus can't be written to the database yet // that are not the lowest number and thus can't be written to the database yet
@ -106,19 +106,30 @@ impl InstanceWorker {
} else { } else {
// send a new activity if there is one // send a new activity if there is one
self.inbox_collector.update_communities().await?; self.inbox_collector.update_communities().await?;
let next_id = { let next_id_to_send = ActivityId(last_sent_id.0 + 1);
// calculate next id to send based on the last id and the in flight requests {
// sanity check: calculate next id to send based on the last id and the in flight requests
let last_successful_id = self let last_successful_id = self
.state .state
.last_successful_id .last_successful_id
.map(|e| e.0) .map(|e| e.0)
.expect("set above"); .expect("set above");
ActivityId(last_successful_id + (successfuls.len() as i64) + in_flight + 1) let expected_next_id = last_successful_id + (successfuls.len() as i64) + in_flight + 1;
}; // compare to next id based on incrementing
if next_id > latest_id { if expected_next_id != next_id_to_send.0 {
anyhow::bail!(
"{}: next id to send is not as expected: {:?} != {:?}",
self.instance.domain,
expected_next_id,
next_id_to_send
)
}
}
if next_id_to_send > newest_id {
// lazily fetch latest id only if we have cought up // lazily fetch latest id only if we have cought up
latest_id = self.get_latest_id().await?; newest_id = self.get_latest_ids().await?.1;
if next_id > latest_id { if next_id_to_send > newest_id {
// no more work to be done, wait before rechecking // no more work to be done, wait before rechecking
tokio::select! { tokio::select! {
() = sleep(*WORK_FINISHED_RECHECK_DELAY) => {}, () = sleep(*WORK_FINISHED_RECHECK_DELAY) => {},
@ -128,8 +139,9 @@ impl InstanceWorker {
} }
} }
in_flight += 1; in_flight += 1;
last_sent_id = next_id_to_send;
self self
.spawn_send_if_needed(next_id, report_send_result.clone()) .spawn_send_if_needed(next_id_to_send, report_send_result.clone())
.await?; .await?;
} }
} }
@ -164,17 +176,20 @@ impl InstanceWorker {
Ok(()) Ok(())
} }
/// get newest activity id and set it as last_successful_id if it's the first time this instance is seen /// return the last successfully sent id and the newest activity id in the database
async fn get_latest_id(&mut self) -> Result<ActivityId> { /// sets last_successful_id in database if it's the first time this instance is seen
async fn get_latest_ids(&mut self) -> Result<(ActivityId, ActivityId)> {
let latest_id = get_latest_activity_id(&mut self.pool()).await?; let latest_id = get_latest_activity_id(&mut self.pool()).await?;
if self.state.last_successful_id.is_none() { if let Some(last) = self.state.last_successful_id {
Ok((last, latest_id))
} else {
// this is the initial creation (instance first seen) of the federation queue for this instance // this is the initial creation (instance first seen) of the federation queue for this instance
// skip all past activities: // skip all past activities:
self.state.last_successful_id = Some(latest_id); self.state.last_successful_id = Some(latest_id);
// save here to ensure it's not read as 0 again later if no activities have happened // save here to ensure it's not read as 0 again later if no activities have happened
self.save_and_send_state().await?; self.save_and_send_state().await?;
Ok((latest_id, latest_id))
} }
Ok(latest_id)
} }
async fn handle_send_results( async fn handle_send_results(
@ -234,11 +249,12 @@ impl InstanceWorker {
force_write: bool, force_write: bool,
) -> Result<()> { ) -> Result<()> {
let Some(mut last_id) = self.state.last_successful_id else { let Some(mut last_id) = self.state.last_successful_id else {
tracing::warn!("should be impossible: last successful id is None"); tracing::warn!("{} should be impossible: last successful id is None", self.instance.domain);
return Ok(()); return Ok(());
}; };
tracing::debug!( tracing::debug!(
"last: {:?}, next: {:?}, currently in successfuls: {:?}", "{} last: {:?}, next: {:?}, currently in successfuls: {:?}",
self.instance.domain,
last_id, last_id,
successfuls.peek(), successfuls.peek(),
successfuls.iter() successfuls.iter()