feat: reuse existing connections in background_fetch() if I/O is started

This commit is contained in:
link2xt
2024-10-04 15:58:16 +00:00
parent 129be3aa27
commit d33909a054

View File

@@ -515,8 +515,11 @@ impl Context {
Ok(val) Ok(val)
} }
/// Does a background fetch /// Does a single round of fetching from IMAP and returns.
/// pauses the scheduler and does one imap fetch, then unpauses and returns ///
/// Can be used even if I/O is currently stopped.
/// If I/O is currently stopped, starts a new IMAP connection
/// and fetches from Inbox and DeltaChat folders.
pub async fn background_fetch(&self) -> Result<()> { pub async fn background_fetch(&self) -> Result<()> {
if !(self.is_configured().await?) { if !(self.is_configured().await?) {
return Ok(()); return Ok(());
@@ -524,35 +527,61 @@ impl Context {
let address = self.get_primary_self_addr().await?; let address = self.get_primary_self_addr().await?;
let time_start = tools::Time::now(); let time_start = tools::Time::now();
info!(self, "background_fetch started fetching {address}"); info!(self, "background_fetch started fetching {address}.");
let _pause_guard = self.scheduler.pause(self.clone()).await?; if self.scheduler.is_running().await {
self.scheduler.maybe_network().await;
// connection // Wait until fetching is finished.
let mut connection = Imap::new_configured(self, channel::bounded(1).1).await?; // Ideally we could wait for connectivity change events,
let mut session = connection.prepare(self).await?; // but sleep loop is good enough.
// fetch imap folders // First 100 ms sleep in chunks of 10 ms.
for folder_meaning in [FolderMeaning::Inbox, FolderMeaning::Mvbox] { for _ in 0..10 {
let (_, watch_folder) = convert_folder_meaning(self, folder_meaning).await?; if self.all_work_done().await {
connection break;
.fetch_move_delete(self, &mut session, &watch_folder, folder_meaning) }
.await?; tokio::time::sleep(std::time::Duration::from_millis(10)).await;
} }
// update quota (to send warning if full) - but only check it once in a while // If we are not finished in 100 ms, keep waking up every 100 ms.
if self while !self.all_work_done().await {
.quota_needs_update(DC_BACKGROUND_FETCH_QUOTA_CHECK_RATELIMIT) tokio::time::sleep(std::time::Duration::from_millis(100)).await;
.await }
{ } else {
if let Err(err) = self.update_recent_quota(&mut session).await { // Pause the scheduler to ensure another connection does not start
warn!(self, "Failed to update quota: {err:#}."); // while we are fetching on a dedicated connection.
let _pause_guard = self.scheduler.pause(self.clone()).await?;
// Start a new dedicated connection.
let mut connection = Imap::new_configured(self, channel::bounded(1).1).await?;
let mut session = connection.prepare(self).await?;
// Fetch IMAP folders.
// Inbox is fetched before Mvbox because fetching from Inbox
// may result in moving some messages to Mvbox.
for folder_meaning in [FolderMeaning::Inbox, FolderMeaning::Mvbox] {
let (_folder_config, watch_folder) =
convert_folder_meaning(self, folder_meaning).await?;
connection
.fetch_move_delete(self, &mut session, &watch_folder, folder_meaning)
.await?;
}
// Update quota (to send warning if full) - but only check it once in a while.
if self
.quota_needs_update(DC_BACKGROUND_FETCH_QUOTA_CHECK_RATELIMIT)
.await
{
if let Err(err) = self.update_recent_quota(&mut session).await {
warn!(self, "Failed to update quota: {err:#}.");
}
} }
} }
info!( info!(
self, self,
"background_fetch done for {address} took {:?}", "background_fetch done for {address} took {:?}.",
time_elapsed(&time_start), time_elapsed(&time_start),
); );