Skip to content

Commit 21cbe7e

Browse files
committed
feat: fetch new messages immediately after IDLE to reduce delay
1 parent 9ef5755 commit 21cbe7e

File tree

2 files changed

+37
-36
lines changed

2 files changed

+37
-36
lines changed

src/imap/idle.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ 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!(context, "UIDNEXT is not set, skipping IDLE to update UIDVALIDITY/UIDNEXT and fetch");
31+
return Ok(self)
32+
}
33+
2634
self.select_folder(context, Some(folder)).await?;
2735

2836
if self.server_sent_unsolicited_exists(context)? {
@@ -37,9 +45,6 @@ impl Session {
3745
.await
3846
.context("STATUS (UIDNEXT) error for {folder:?}")?;
3947
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}"))?;
4348
if uid_next > expected_uid_next {
4449
info!(
4550
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
@@ -605,12 +594,9 @@ async fn fetch_idle(ctx: &Context, connection: &mut Imap, folder_meaning: Folder
605594
"IMAP session does not support IDLE, going to fake idle."
606595
);
607596
connection
608-
.fake_idle(ctx, Some(watch_folder), folder_meaning)
597+
.fake_idle(ctx, Some(watch_folder.clone()), folder_meaning)
609598
.await;
610-
return;
611-
}
612-
613-
if ctx
599+
} else if ctx
614600
.get_config_bool(Config::DisableIdle)
615601
.await
616602
.context("Failed to get disable_idle config")
@@ -619,28 +605,38 @@ async fn fetch_idle(ctx: &Context, connection: &mut Imap, folder_meaning: Folder
619605
{
620606
info!(ctx, "IMAP IDLE is disabled, going to fake idle.");
621607
connection
622-
.fake_idle(ctx, Some(watch_folder), folder_meaning)
608+
.fake_idle(ctx, Some(watch_folder.clone()), folder_meaning)
623609
.await;
624-
return;
610+
} else {
611+
info!(ctx, "IMAP session supports IDLE, using it.");
612+
match session
613+
.idle(
614+
ctx,
615+
connection.idle_interrupt_receiver.clone(),
616+
&watch_folder,
617+
)
618+
.await
619+
.context("idle")
620+
{
621+
Ok(session) => {
622+
connection.session = Some(session);
623+
}
624+
Err(err) => {
625+
connection.trigger_reconnect(ctx);
626+
warn!(ctx, "{:#}", err);
627+
}
628+
}
625629
}
626630

627-
info!(ctx, "IMAP session supports IDLE, using it.");
628-
match session
629-
.idle(
630-
ctx,
631-
connection.idle_interrupt_receiver.clone(),
632-
&watch_folder,
633-
)
631+
// Fetch the watched folder
632+
// immediately after IDLE to reduce message delivery latency.
633+
if let Err(err) = connection
634+
.fetch_move_delete(ctx, &watch_folder, folder_meaning)
634635
.await
635-
.context("idle")
636+
.context("fetch_move_delete")
636637
{
637-
Ok(session) => {
638-
connection.session = Some(session);
639-
}
640-
Err(err) => {
641-
connection.trigger_reconnect(ctx);
642-
warn!(ctx, "{:#}", err);
643-
}
638+
connection.trigger_reconnect(ctx);
639+
warn!(ctx, "{:#}", err);
644640
}
645641
}
646642

0 commit comments

Comments
 (0)