You could use a builtin timer class, there are various.
You could also use my base class for an async ticker:
/// <summary>
/// Base class for an async ticker (runs a function every period or 'tick')
/// Adapted from <see href="https://stackoverflow.com/a/62724908/4122889"/>
/// NOTE this class was not designed to handle UI in any way - it could, but test beforehand!
/// </summary>
public abstract class TickerBase
{
#region Properties and Fields
private readonly ILogger<TickerBase> _logger;
public TimeSpan Interval { get; protected set; }
private readonly Action<ILogger, string, Exception> _tickerStarted = LoggerMessage.Define<string>(LogLevel.Trace, new EventId(0, nameof(_tickerStarted)), "Starting ticker: {0}");
private readonly Action<ILogger, string, Exception> _tickerCancelled = LoggerMessage.Define<string>(LogLevel.Trace, new EventId(0, nameof(_tickerCancelled)), "Cancellation requested: {0}");
#endregion
#region Construction and Destruction
protected TickerBase(ILoggerFactory loggerFactory, TimeSpan interval)
{
if(interval == default) throw new ArgumentOutOfRangeException(nameof(interval), "Interval was its default value");
_logger = loggerFactory.CreateLogger<TickerBase>() ?? throw new ArgumentNullException(nameof(loggerFactory));
Interval = interval;
}
#endregion
#region Starting
/// <summary>
/// Start the ticker. Don't await this function, it will run indefinitely.
/// Be mindful of exceptions.
/// Calling this function more than once will start more tasks and thus more tickers.
/// </summary>
/// <param name="ctx">cancellation token to cancel the timer</param>
/// <returns></returns>
public async Task StartAsync(CancellationToken ctx = default)
{
// Log starting and stopping of ticker(s)
_tickerStarted(_logger, GetType().Name, null);
ctx.Register(() => _tickerCancelled(_logger, GetType().Name, null));
while (true)
{
var delayTask = Task.Delay(Interval, ctx);
await OnTickAsync(ctx)
.ConfigureAwait(false);
await delayTask
.ConfigureAwait(false);
ctx.ThrowIfCancellationRequested();
}
// ReSharper disable once FunctionNeverReturns Reason: as designed
}
protected abstract Task OnTickAsync(CancellationToken ctx = default);
}
#endregion
}