feat(infrastructure): add TriggerSync to EmailSyncWorker for on-demand immediate sync; fix cancellation propagation after delay
This commit is contained in:
@@ -14,6 +14,20 @@ public class EmailSyncWorker(IOptions<EmailAccountsOptions> Options, IServicePro
|
|||||||
{
|
{
|
||||||
private readonly string DefaultFolder = "INBOX";
|
private readonly string DefaultFolder = "INBOX";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signals the current <see cref="Task.Delay"/> to complete immediately,
|
||||||
|
/// causing the sync loop to start the next cycle without waiting.
|
||||||
|
/// A new TCS is created at the start of each delay so repeated triggers work correctly.
|
||||||
|
/// </summary>
|
||||||
|
private volatile TaskCompletionSource<bool> _syncTrigger = new(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggers an immediate sync cycle by completing the current delay early.
|
||||||
|
/// Safe to call from any thread or HTTP request at any time.
|
||||||
|
/// If a sync is already running, the trigger is ignored — the next cycle starts normally.
|
||||||
|
/// </summary>
|
||||||
|
public void TriggerSync() => _syncTrigger.TrySetResult(true);
|
||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
await UpsertSeedEmailAccount(stoppingToken);
|
await UpsertSeedEmailAccount(stoppingToken);
|
||||||
@@ -33,7 +47,15 @@ public class EmailSyncWorker(IOptions<EmailAccountsOptions> Options, IServicePro
|
|||||||
await SyncAccountAsync(account, imapService, pop3Service, stoppingToken);
|
await SyncAccountAsync(account, imapService, pop3Service, stoppingToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(interval, stoppingToken).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);
|
// Reset trigger before waiting so any TriggerSync() call during the delay is caught
|
||||||
|
_syncTrigger = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
|
var delay = Task.Delay(interval, stoppingToken);
|
||||||
|
var triggered = _syncTrigger.Task;
|
||||||
|
await Task.WhenAny(delay, triggered).ConfigureAwait(false);
|
||||||
|
|
||||||
|
// Propagate cancellation if the host is stopping
|
||||||
|
stoppingToken.ThrowIfCancellationRequested();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user