Skip to content

Commit 2ca0ec2

Browse files
committed
feat: fetch new messages immediately after IDLE to reduce delay
1 parent 56b4bb0 commit 2ca0ec2

File tree

2 files changed

+40
-36
lines changed

2 files changed

+40
-36
lines changed

src/imap/idle.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ impl Session {
2323
) -> Result<Self> {
2424
use futures::future::FutureExt;
2525

26+
let expected_uid_next = get_uid_next(context, folder)
27+
.await
28+
.with_context(|| format!("failed to get old UID NEXT for folder {folder}"))?;
29+
if expected_uid_next == 0 {
30+
info!(
31+
context,
32+
"UIDNEXT is not set, skipping IDLE to update UIDVALIDITY/UIDNEXT and fetch"
33+
);
34+
return Ok(self);
35+
}
36+
2637
self.select_folder(context, Some(folder)).await?;
2738

2839
if self.server_sent_unsolicited_exists(context)? {
@@ -37,9 +48,6 @@ impl Session {
3748
.await
3849
.context("STATUS (UIDNEXT) error for {folder:?}")?;
3950
if let Some(uid_next) = status.uid_next {
40-
let expected_uid_next = get_uid_next(context, folder)
41-
.await
42-
.with_context(|| format!("failed to get old UID NEXT for folder {folder}"))?;
4351
if uid_next > expected_uid_next {
4452
info!(
4553
context,

src/scheduler.rs

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -526,17 +526,6 @@ async fn fetch_idle(ctx: &Context, connection: &mut Imap, folder_meaning: Folder
526526
}
527527
}
528528

529-
// Fetch the watched folder.
530-
if let Err(err) = connection
531-
.fetch_move_delete(ctx, &watch_folder, folder_meaning)
532-
.await
533-
.context("fetch_move_delete")
534-
{
535-
connection.trigger_reconnect(ctx);
536-
warn!(ctx, "{:#}", err);
537-
return;
538-
}
539-
540529
// Mark expired messages for deletion. Marked messages will be deleted from the server
541530
// on the next iteration of `fetch_move_delete`. `delete_expired_imap_messages` is not
542531
// called right before `fetch_move_delete` because it is not well optimized and would
@@ -585,12 +574,9 @@ async fn fetch_idle(ctx: &Context, connection: &mut Imap, folder_meaning: Folder
585574
"IMAP session does not support IDLE, going to fake idle."
586575
);
587576
connection
588-
.fake_idle(ctx, Some(watch_folder), folder_meaning)
577+
.fake_idle(ctx, Some(watch_folder.clone()), folder_meaning)
589578
.await;
590-
return;
591-
}
592-
593-
if ctx
579+
} else if ctx
594580
.get_config_bool(Config::DisableIdle)
595581
.await
596582
.context("Failed to get disable_idle config")
@@ -599,28 +585,38 @@ async fn fetch_idle(ctx: &Context, connection: &mut Imap, folder_meaning: Folder
599585
{
600586
info!(ctx, "IMAP IDLE is disabled, going to fake idle.");
601587
connection
602-
.fake_idle(ctx, Some(watch_folder), folder_meaning)
588+
.fake_idle(ctx, Some(watch_folder.clone()), folder_meaning)
603589
.await;
604-
return;
590+
} else {
591+
info!(ctx, "IMAP session supports IDLE, using it.");
592+
match session
593+
.idle(
594+
ctx,
595+
connection.idle_interrupt_receiver.clone(),
596+
&watch_folder,
597+
)
598+
.await
599+
.context("idle")
600+
{
601+
Ok(session) => {
602+
connection.session = Some(session);
603+
}
604+
Err(err) => {
605+
connection.trigger_reconnect(ctx);
606+
warn!(ctx, "{:#}", err);
607+
}
608+
}
605609
}
606610

607-
info!(ctx, "IMAP session supports IDLE, using it.");
608-
match session
609-
.idle(
610-
ctx,
611-
connection.idle_interrupt_receiver.clone(),
612-
&watch_folder,
613-
)
611+
// Fetch the watched folder
612+
// immediately after IDLE to reduce message delivery latency.
613+
if let Err(err) = connection
614+
.fetch_move_delete(ctx, &watch_folder, folder_meaning)
614615
.await
615-
.context("idle")
616+
.context("fetch_move_delete")
616617
{
617-
Ok(session) => {
618-
connection.session = Some(session);
619-
}
620-
Err(err) => {
621-
connection.trigger_reconnect(ctx);
622-
warn!(ctx, "{:#}", err);
623-
}
618+
connection.trigger_reconnect(ctx);
619+
warn!(ctx, "{:#}", err);
624620
}
625621
}
626622

0 commit comments

Comments
 (0)