Auto sync trigger and cancellation support.
This commit is contained in:
@@ -26,6 +26,7 @@ public class SynchronizationManager : ISynchronizationManager
|
||||
public static SynchronizationManager Instance => _instance.Value;
|
||||
|
||||
private readonly ConcurrentDictionary<Guid, IWinoSynchronizerBase> _synchronizerCache = new();
|
||||
private readonly ConcurrentDictionary<Guid, CancellationTokenSource> _accountSynchronizationCancellationSources = new();
|
||||
private readonly SemaphoreSlim _initializationSemaphore = new(1, 1);
|
||||
private readonly ILogger _logger = Log.ForContext<SynchronizationManager>();
|
||||
|
||||
@@ -141,9 +142,14 @@ public class SynchronizationManager : ISynchronizationManager
|
||||
_logger.Information("Starting mail synchronization for account {AccountId} with type {SyncType}",
|
||||
options.AccountId, options.Type);
|
||||
|
||||
var accountCancellationSource = _accountSynchronizationCancellationSources.GetOrAdd(options.AccountId, _ => new CancellationTokenSource());
|
||||
using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(
|
||||
cancellationToken,
|
||||
accountCancellationSource.Token);
|
||||
|
||||
try
|
||||
{
|
||||
var result = await synchronizer.SynchronizeMailsAsync(options, cancellationToken);
|
||||
var result = await synchronizer.SynchronizeMailsAsync(options, linkedCancellationTokenSource.Token);
|
||||
|
||||
_logger.Information("Mail synchronization completed for account {AccountId} with state {State}",
|
||||
options.AccountId, result.CompletedState);
|
||||
@@ -156,6 +162,11 @@ public class SynchronizationManager : ISynchronizationManager
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.Information("Mail synchronization canceled for account {AccountId}", options.AccountId);
|
||||
return MailSynchronizationResult.Canceled;
|
||||
}
|
||||
catch (AuthenticationAttentionException authEx)
|
||||
{
|
||||
_logger.Warning("Account {AccountId} requires attention due to authentication issues", options.AccountId);
|
||||
@@ -350,9 +361,14 @@ public class SynchronizationManager : ISynchronizationManager
|
||||
_logger.Information("Starting calendar synchronization for account {AccountId} with type {SyncType}",
|
||||
options.AccountId, options.Type);
|
||||
|
||||
var accountCancellationSource = _accountSynchronizationCancellationSources.GetOrAdd(options.AccountId, _ => new CancellationTokenSource());
|
||||
using var linkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(
|
||||
cancellationToken,
|
||||
accountCancellationSource.Token);
|
||||
|
||||
try
|
||||
{
|
||||
var result = await synchronizer.SynchronizeCalendarEventsAsync(options, cancellationToken);
|
||||
var result = await synchronizer.SynchronizeCalendarEventsAsync(options, linkedCancellationTokenSource.Token);
|
||||
|
||||
_logger.Information("Calendar synchronization completed for account {AccountId} with state {State}",
|
||||
options.AccountId, result.CompletedState);
|
||||
@@ -363,6 +379,11 @@ public class SynchronizationManager : ISynchronizationManager
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.Information("Calendar synchronization canceled for account {AccountId}", options.AccountId);
|
||||
return CalendarSynchronizationResult.Canceled;
|
||||
}
|
||||
catch (AuthenticationAttentionException authEx)
|
||||
{
|
||||
_logger.Warning("Account {AccountId} requires attention due to authentication issues", options.AccountId);
|
||||
@@ -491,6 +512,38 @@ public class SynchronizationManager : ISynchronizationManager
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels all in-flight synchronizations for the given account.
|
||||
/// </summary>
|
||||
/// <param name="accountId">Account ID to cancel synchronizations for</param>
|
||||
public Task CancelSynchronizationsAsync(Guid accountId)
|
||||
{
|
||||
EnsureInitialized();
|
||||
|
||||
if (_accountSynchronizationCancellationSources.TryRemove(accountId, out var cancellationSource))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!cancellationSource.IsCancellationRequested)
|
||||
{
|
||||
cancellationSource.Cancel();
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
finally
|
||||
{
|
||||
cancellationSource.Dispose();
|
||||
}
|
||||
|
||||
_logger.Information("Canceled ongoing synchronizations for account {AccountId}", accountId);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the synchronizer for the given account.
|
||||
/// </summary>
|
||||
@@ -498,6 +551,7 @@ public class SynchronizationManager : ISynchronizationManager
|
||||
public async Task DestroySynchronizerAsync(Guid accountId)
|
||||
{
|
||||
EnsureInitialized();
|
||||
await CancelSynchronizationsAsync(accountId);
|
||||
|
||||
if (_synchronizerCache.TryRemove(accountId, out var synchronizer))
|
||||
{
|
||||
@@ -506,6 +560,10 @@ public class SynchronizationManager : ISynchronizationManager
|
||||
await synchronizer.KillSynchronizerAsync();
|
||||
_logger.Information("Destroyed synchronizer for account {AccountId}", accountId);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.Information("Synchronizer destruction canceled for account {AccountId}", accountId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Failed to destroy synchronizer for account {AccountId}", accountId);
|
||||
|
||||
Reference in New Issue
Block a user