From 4a5e99c48ee833540458c8cf9b440b99c6096513 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Fri, 6 Dec 2019 01:57:57 +0100 Subject: [PATCH] make idle wait only as long as the next job wants to run --- examples/repl/cmdline.rs | 2 +- examples/repl/main.rs | 2 +- examples/simple.rs | 2 +- src/imap/idle.rs | 30 +++++++++++++++++++++++++----- src/imap/mod.rs | 2 +- src/job_thread.rs | 15 ++++++++++----- 6 files changed, 39 insertions(+), 14 deletions(-) diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 28e15a2e1..11c063c3c 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -491,7 +491,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> { println!("{:#?}", context.get_info()); } "interrupt" => { - interrupt_inbox_idle(context, true); + interrupt_inbox_idle(context); } "maybenetwork" => { maybe_network(context); diff --git a/examples/repl/main.rs b/examples/repl/main.rs index 178f4fb0d..1dc206419 100644 --- a/examples/repl/main.rs +++ b/examples/repl/main.rs @@ -202,7 +202,7 @@ fn stop_threads(context: &Context) { println!("Stopping threads"); IS_RUNNING.store(false, Ordering::Relaxed); - interrupt_inbox_idle(context, true); + interrupt_inbox_idle(context); interrupt_mvbox_idle(context); interrupt_sentbox_idle(context); interrupt_smtp_idle(context); diff --git a/examples/simple.rs b/examples/simple.rs index 71917e7c1..49a058a36 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -104,7 +104,7 @@ fn main() { println!("stopping threads"); *running.write().unwrap() = false; - deltachat::job::interrupt_inbox_idle(&ctx, true); + deltachat::job::interrupt_inbox_idle(&ctx); deltachat::job::interrupt_smtp_idle(&ctx); println!("joining"); diff --git a/src/imap/idle.rs b/src/imap/idle.rs index 38b546434..a435ae659 100644 --- a/src/imap/idle.rs +++ b/src/imap/idle.rs @@ -3,6 +3,7 @@ use super::Imap; use async_imap::extensions::idle::IdleResponse; use async_std::prelude::*; use async_std::task; +use core::cmp::min; use std::sync::atomic::Ordering; use std::time::{Duration, SystemTime}; @@ -45,7 +46,12 @@ impl Imap { task::block_on(async move { self.config.read().await.can_idle }) } - pub fn idle(&self, context: &Context, watch_folder: Option) -> Result<()> { + pub fn idle( + &self, + context: &Context, + watch_folder: Option, + timeout: Duration, + ) -> Result<()> { task::block_on(async move { if !self.can_idle() { return Err(Error::IdleAbilityMissing); @@ -58,7 +64,7 @@ impl Imap { self.select_folder(context, watch_folder.clone()).await?; let session = self.session.lock().await.take(); - let timeout = Duration::from_secs(23 * 60); + let max_duration = Duration::from_secs(23 * 60); if let Some(session) = session { match session.idle() { // BEWARE: If you change the Secure branch you @@ -67,8 +73,8 @@ impl Imap { if let Err(err) = handle.init().await { return Err(Error::IdleProtocolFailed(err)); } - - let (idle_wait, interrupt) = handle.wait_with_timeout(timeout); + let real_timeout = min(timeout, max_duration); + let (idle_wait, interrupt) = handle.wait_with_timeout(real_timeout); *self.interrupt.lock().await = Some(interrupt); if self.skip_next_idle_wait.load(Ordering::SeqCst) { @@ -178,7 +184,12 @@ impl Imap { }) } - pub(crate) fn fake_idle(&self, context: &Context, watch_folder: Option) { + pub(crate) fn fake_idle( + &self, + context: &Context, + watch_folder: Option, + timeout: Duration, + ) { // Idle using polling. This is also needed if we're not yet configured - // in this case, we're waiting for a configure job (and an interrupt). task::block_on(async move { @@ -213,6 +224,15 @@ impl Imap { break; } info!(context, "fake_idle is connected"); + + if SystemTime::now() + .duration_since(fake_idle_start_time) + .unwrap_or_default() + > timeout + { + info!(context, "fake_idle stopping as jobs need running"); + break; + } // we are connected, let's see if fetching messages results // in anything. If so, we behave as if IDLE had data but // will have already fetched the messages so perform_*_fetch diff --git a/src/imap/mod.rs b/src/imap/mod.rs index 7079fd462..60110b345 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -1202,7 +1202,7 @@ fn precheck_imf(context: &Context, rfc724_mid: &str, server_folder: &str, server { if old_server_folder.is_empty() && old_server_uid == 0 { info!(context, "[move] detected bbc-self {}", rfc724_mid,); - do_heuristics_moves(context, server_folder.as_ref(), msg_id); + do_heuristics_moves(context, server_folder, msg_id); add_job_no_interrupt( context, Action::MarkseenMsgOnImap, diff --git a/src/job_thread.rs b/src/job_thread.rs index 3253232c7..c10dabecc 100644 --- a/src/job_thread.rs +++ b/src/job_thread.rs @@ -134,13 +134,18 @@ impl JobThread { } pub fn idle(&self, context: &Context, use_network: bool) { + // standard idle wait timeout + let mut timeout = Duration::from_secs(23 * 60); + { let &(ref lock, ref cvar) = &*self.state.clone(); let mut state = lock.lock().unwrap(); - if self.folder_config_name == "INBOX" { - let duration = get_next_wakeup_time(context, Thread::Imap); - if duration <= Duration::from_millis(1) { + // if we are in the inbox (job) thread + // we check if a job is due. + if self.folder_config_name == "configured_inbox_folder" { + timeout = get_next_wakeup_time(context, Thread::Imap); + if timeout <= Duration::from_millis(20) { info!( context, "INBOX-IDLE will not be started because of waiting jobs." @@ -178,7 +183,7 @@ impl JobThread { } else { let watch_folder = self.get_watch_folder(context); info!(context, "{} started...", prefix); - let res = self.imap.idle(context, watch_folder); + let res = self.imap.idle(context, watch_folder, timeout); info!(context, "{} ended...", prefix); if let Err(err) = res { warn!(context, "{} failed: {} -> reconnecting", prefix, err); @@ -198,7 +203,7 @@ impl JobThread { }; if do_fake_idle { let watch_folder = self.get_watch_folder(context); - self.imap.fake_idle(context, watch_folder); + self.imap.fake_idle(context, watch_folder, timeout); } self.state.0.lock().unwrap().using_handle = false;