Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use PeriodicTimer in the async timer #4004

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
83 changes: 36 additions & 47 deletions src/ServiceControl.Infrastructure/AsyncTimer.cs
@@ -1,4 +1,6 @@
namespace ServiceControl.Infrastructure.BackgroundTasks
#nullable enable

namespace ServiceControl.Infrastructure.BackgroundTasks
{
using System;
using System.Threading;
Expand All @@ -18,69 +20,56 @@ public TimerJob(Func<CancellationToken, Task<TimerJobExecutionResult>> callback,
tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;

task = Task.Run(async () =>
timerBody = TimerBody(callback, due, interval, errorCallback, token);
}

async Task TimerBody(Func<CancellationToken, Task<TimerJobExecutionResult>> callback, TimeSpan due, TimeSpan interval, Action<Exception> errorCallback, CancellationToken cancellationToken)
{
try
{
try
{
await Task.Delay(due, token).ConfigureAwait(false);
await Task.Delay(due, cancellationToken).ConfigureAwait(false);

while (!token.IsCancellationRequested)
using var timer = new PeriodicTimer(interval);
while (await timer.WaitForNextTickAsync(cancellationToken).ConfigureAwait(false))
{
try
{
try
TimerJobExecutionResult result;
do
{
var result = await callback(token).ConfigureAwait(false);
result = await callback(cancellationToken).ConfigureAwait(false);

if (result == TimerJobExecutionResult.DoNotContinueExecuting)
{
tokenSource.Cancel();
return;
}
else if (result == TimerJobExecutionResult.ScheduleNextExecution)
{
await Task.Delay(interval, token).ConfigureAwait(false);
}

//Otherwise execute immediately
}
catch (OperationCanceledException)
{
// no-op
}
catch (Exception ex)
{
errorCallback(ex);
}
} while (result == TimerJobExecutionResult.ExecuteImmediately);
}
catch (OperationCanceledException)
{
// no-op
}
catch (Exception ex)
{
errorCallback(ex);
}
}
catch (OperationCanceledException)
{
// no-op
}
}, CancellationToken.None);
}
catch (OperationCanceledException)
{
// no-op
}
}

public async Task Stop()
{
if (tokenSource == null)
{
return;
}

tokenSource.Cancel();
await tokenSource.CancelAsync().ConfigureAwait(false);
tokenSource.Dispose();

if (task != null)
{
try
{
await task.ConfigureAwait(false);
}
catch (OperationCanceledException)
{
//NOOP
}
}
await timerBody.ConfigureAwait(false);
}

Task task;
Task timerBody;
CancellationTokenSource tokenSource;
}

Expand Down
Expand Up @@ -28,7 +28,7 @@ public void Start()
timer = scheduler.Schedule(
Run,
TimeSpan.Zero,
check.Interval ?? TimeSpan.MaxValue,
check.Interval ?? Timeout.InfiniteTimeSpan,
e => { /* Should not happen */ }
);
}
Expand Down