Refactor IMAP sync caching and improve thread safety
Replaced `IMemoryCache` with a thread-safe `ConcurrentDictionary` for managing IMAP sync dates in `LimilabsImapEmailService`. Added `GetLastImapSyncDate` and `SetLastImapSyncDate` methods to handle cache operations. Updated the `IImapEmailService` interface to include `GetLastImapSyncDate`. Simplified the `MarkAsSeenAsync` method signature for better readability. Introduced a private record type `ImapCacheKey` to encapsulate cache keys.
This commit is contained in:
@@ -29,5 +29,13 @@ public interface IImapEmailService
|
||||
long uid,
|
||||
string folder = "INBOX",
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last IMAP sync date for the specified account and folder.
|
||||
/// </summary>
|
||||
/// <param name="accountId"></param>
|
||||
/// <param name="folder"></param>
|
||||
/// <returns></returns>
|
||||
DateTime? GetLastImapSyncDate(int accountId, string folder = "INBOX");
|
||||
}
|
||||
#endif
|
||||
@@ -5,8 +5,8 @@ using DigitalData.MessagingService.Domain.Entities;
|
||||
using DigitalData.MessagingService.Infrastructure.Services.Extensions;
|
||||
using Limilabs.Client.IMAP;
|
||||
using Limilabs.Mail;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Text;
|
||||
|
||||
namespace DigitalData.MessagingService.Infrastructure.Services;
|
||||
@@ -15,7 +15,7 @@ namespace DigitalData.MessagingService.Infrastructure.Services;
|
||||
/// IMAP email service using Limilabs Mail.dll.
|
||||
/// Opens a fresh connection per call — stateless and thread-safe.
|
||||
/// </summary>
|
||||
public class LimilabsImapEmailService(ILogger<LimilabsImapEmailService> Logger, IRepository<ReceivedEmail> Repository, IMemoryCache Cache) : IImapEmailService
|
||||
public class LimilabsImapEmailService(ILogger<LimilabsImapEmailService> Logger, IRepository<ReceivedEmail> Repository) : IImapEmailService
|
||||
{
|
||||
private static readonly string CacheKeyPrefix = Guid.NewGuid().ToString();
|
||||
|
||||
@@ -34,7 +34,7 @@ public class LimilabsImapEmailService(ILogger<LimilabsImapEmailService> Logger,
|
||||
// Server-side: only date range; all other filters are applied in-process after cache retrieval
|
||||
List<ICriterion> criterions = [];
|
||||
|
||||
var since = Cache.GetLastImapSyncDate(account.Id, folder);
|
||||
var since = GetLastImapSyncDate(account.Id, folder);
|
||||
|
||||
if (since is not null && since != default)
|
||||
criterions.Add(Expression.SentSince(since.Value));
|
||||
@@ -112,7 +112,7 @@ public class LimilabsImapEmailService(ILogger<LimilabsImapEmailService> Logger,
|
||||
|
||||
emails.Add(email);
|
||||
|
||||
Cache.SetLastImapSyncDate(account.Id, folder, operationStartTime);
|
||||
SetLastImapSyncDate(account.Id, folder, operationStartTime);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -136,11 +136,7 @@ public class LimilabsImapEmailService(ILogger<LimilabsImapEmailService> Logger,
|
||||
}
|
||||
}
|
||||
|
||||
public async Task MarkAsSeenAsync(
|
||||
EmailAccount account,
|
||||
long uid,
|
||||
string folder = "INBOX",
|
||||
CancellationToken cancel = default)
|
||||
public async Task MarkAsSeenAsync(EmailAccount account, long uid, string folder = "INBOX", CancellationToken cancel = default)
|
||||
{
|
||||
using var imap = await OpenAsync(account, folder, cancel);
|
||||
try
|
||||
@@ -173,4 +169,21 @@ public class LimilabsImapEmailService(ILogger<LimilabsImapEmailService> Logger,
|
||||
|
||||
return imap;
|
||||
}
|
||||
|
||||
#region IMAP Last Sync Date Cache
|
||||
private readonly ConcurrentDictionary<ImapCacheKey, DateTime> _cache = new();
|
||||
|
||||
private record ImapCacheKey(int AccountId, string Folder);
|
||||
|
||||
public DateTime? GetLastImapSyncDate(int accountId, string folder = "INBOX")
|
||||
{
|
||||
return _cache.GetValueOrDefault(new ImapCacheKey(accountId, folder));
|
||||
}
|
||||
|
||||
private void SetLastImapSyncDate(int accountId, string folder, DateTime date)
|
||||
{
|
||||
var key = new ImapCacheKey(accountId, folder);
|
||||
_cache[key] = date;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user