chore: remove bb8 pool for IMAP; create a new session per operation to avoid stale connections

This commit is contained in:
rustmailer
2026-01-28 20:41:17 +08:00
parent d63b1e0d7c
commit 579822762f
16 changed files with 186 additions and 296 deletions
+38 -24
View File
@@ -30,8 +30,8 @@ use crate::{
},
SEMAPHORE,
},
context::executors::MAIL_CONTEXT,
error::{code::ErrorCode, BichonError, BichonResult},
imap::executor::ImapExecutor,
indexer::manager::ENVELOPE_INDEX_MANAGER,
},
raise_error,
@@ -55,16 +55,15 @@ pub async fn fetch_and_save_by_date(
direction: FetchDirection,
) -> BichonResult<usize> {
let account_id = account.id;
let executor = MAIL_CONTEXT.imap(account_id).await?;
let mut session = ImapExecutor::create_connection(account_id).await?;
let search_criteria = match direction {
FetchDirection::Since => format!("SINCE {date}"),
FetchDirection::Before => format!("BEFORE {date}"),
};
let uid_list = executor
.uid_search(&mailbox.encoded_name(), &search_criteria)
.await?;
let uid_list =
ImapExecutor::uid_search(&mut session, &mailbox.encoded_name(), &search_criteria).await?;
let len = uid_list.len();
if len == 0 {
@@ -109,12 +108,18 @@ pub async fn fetch_and_save_by_date(
(index + 1) as u32,
)
.await?;
let executor = MAIL_CONTEXT.imap(account_id).await?;
// Fetch metadata for the current batch of UIDs
executor
.uid_batch_retrieve_emails(account_id, mailbox.id, &batch, &mailbox.encoded_name())
.await?;
ImapExecutor::uid_batch_retrieve_emails(
&mut session,
account_id,
mailbox.id,
&batch,
&mailbox.encoded_name(),
)
.await?;
}
session.logout().await.ok();
Ok(len)
}
@@ -153,26 +158,29 @@ pub async fn fetch_and_save_full_mailbox(
"Starting full mailbox sync for '{}', total={}, limit={:?}, batches={}, desc={}",
mailbox.name, total, folder_limit, total_batches, desc
);
let mut session = ImapExecutor::create_connection(account_id).await?;
for page in 1..=total_batches {
AccountRunningState::set_current_sync_batch_number(account_id, mailbox.name.clone(), page)
.await?;
let executor = MAIL_CONTEXT.imap(account_id).await?;
let count = executor
.batch_retrieve_emails(
account_id,
mailbox_id,
page as u64,
page_size as u64,
&mailbox.encoded_name(),
desc,
)
.await?;
let count = ImapExecutor::batch_retrieve_emails(
&mut session,
account_id,
mailbox_id,
page as u64,
page_size as u64,
&mailbox.encoded_name(),
desc,
)
.await?;
inserted_count += count;
info!(
"Batch insertion completed for mailbox: {}, current page: {}, inserted count: {}",
&mailbox.name, page, count
);
}
session.logout().await.ok();
Ok(inserted_count)
}
@@ -423,16 +431,22 @@ async fn perform_incremental_sync(
.await?;
match local_max_uid {
Some(max_uid) => {
let executor = MAIL_CONTEXT.imap(account.id).await?;
let mut session = ImapExecutor::create_connection(account.id).await?;
let before_date = account
.date_before
.as_ref()
.map(|r| r.calculate_date())
.transpose()?;
executor
.fetch_new_mail(account, local_mailbox, max_uid + 1, before_date.as_deref())
.await?;
ImapExecutor::fetch_new_mail(
&mut session,
account,
local_mailbox,
max_uid + 1,
before_date.as_deref(),
)
.await?;
session.logout().await.ok();
}
None => {
info!(
+15 -2
View File
@@ -25,6 +25,7 @@ use crate::{
},
cache::imap::{mailbox::MailBox, sync::flow::FetchDirection},
error::BichonResult,
imap::executor::ImapExecutor,
},
utc_now,
};
@@ -33,7 +34,7 @@ use rebuild::{rebuild_cache, rebuild_cache_by_date};
use std::time::Instant;
use sync_folders::get_sync_folders;
use sync_type::{determine_sync_type, SyncType};
use tracing::debug;
use tracing::{debug, warn};
pub mod flow;
pub mod rebuild;
@@ -48,7 +49,19 @@ pub async fn execute_imap_sync(account: &AccountModel) -> BichonResult<()> {
if matches!(sync_type, SyncType::SkipSync) {
return Ok(());
}
let remote_mailboxes = get_sync_folders(account).await?;
let mut session = ImapExecutor::create_connection(account_id).await?;
let remote_mailboxes = match get_sync_folders(account, &mut session).await {
Ok(mailboxes) => mailboxes,
Err(err) => {
warn!(
account_id = account.id,
error = %err,
"Failed to get sync folders, logging out and skipping this account"
);
return Ok(());
}
};
session.logout().await.ok();
if matches!(sync_type, SyncType::InitialSync) {
AccountRunningState::add(account.id).await?;
// AccountRunningState::set_initial_sync_start(account_id).await?;
-2
View File
@@ -121,7 +121,6 @@ pub async fn rebuild_cache_by_date(
MailBox::batch_insert(remote_mailboxes).await?;
let mut handles = Vec::new();
let local_semaphore = Arc::new(Semaphore::new(DEFAULT_MAX_CONCURRENT_PER_ACCOUNT));
for mailbox in remote_mailboxes {
@@ -164,7 +163,6 @@ pub async fn rebuild_cache_by_date(
tokio::spawn(async move {
let _global_permit = global_permit;
let _local_permit = local_permit;
fetch_and_save_by_date(&account, date.as_str(), &mailbox, direction).await
});
handles.push(handle);
+8 -7
View File
@@ -16,7 +16,6 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use std::collections::BTreeSet;
use crate::{
@@ -24,19 +23,21 @@ use crate::{
modules::{
account::migration::{AccountModel, AccountType},
cache::imap::mailbox::{AttributeEnum, MailBox},
context::executors::MAIL_CONTEXT,
error::{code::ErrorCode, BichonResult},
imap::{executor::ImapExecutor, session::SessionStream},
mailbox::list::convert_names_to_mailboxes,
},
raise_error,
};
use async_imap::types::Name;
use async_imap::{types::Name, Session};
use tracing::{debug, info, warn};
pub async fn get_sync_folders(account: &AccountModel) -> BichonResult<Vec<MailBox>> {
pub async fn get_sync_folders(
account: &AccountModel,
session: &mut Session<Box<dyn SessionStream>>,
) -> BichonResult<Vec<MailBox>> {
assert_eq!(account.account_type, AccountType::IMAP);
let executor = MAIL_CONTEXT.imap(account.id).await?;
let names = executor.list_all_mailboxes().await?;
let names = ImapExecutor::list_all_mailboxes(session).await?;
if names.is_empty() {
warn!(
"Account {}: No mailboxes returned from IMAP server.",
@@ -121,7 +122,7 @@ pub async fn get_sync_folders(account: &AccountModel) -> BichonResult<Vec<MailBo
), ErrorCode::ImapUnexpectedResult));
}
}
convert_names_to_mailboxes(account.id, matched_mailboxes).await
convert_names_to_mailboxes(account.id, session, matched_mailboxes).await
}
pub async fn detect_mailbox_changes(