ASP.NET Core › Background Tasks & Hosted Services

How do you implement a periodic scheduled task using PeriodicTimer instead of Task.Delay, and what problem does it solve?

Intermediate

Answer

PeriodicTimer (introduced in .NET 6) provides an async-friendly, precise interval timer via WaitForNextTickAsync(), avoiding the cumulative drift that naive Task.Delay-based loops can introduce (where each cycle's total duration equals work time plus delay time, drifting over many iterations) -- PeriodicTimer's ticks stay aligned to the original interval regardless of how long each cycle's work takes.
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
    using var timer = new PeriodicTimer(TimeSpan.FromMinutes(5));
    while (await timer.WaitForNextTickAsync(stoppingToken)) {
        await RunScheduledJobAsync();
    }
}
Real-world example A metrics-collection background service switches from Task.Delay to PeriodicTimer to guarantee samples are taken at consistent 5-minute intervals regardless of how long each collection cycle takes, improving the consistency of trend analysis.

Common follow-ups: How does WaitForNextTickAsync behave if the previous tick's work exceeds the interval?;What happens to a PeriodicTimer when it's disposed mid-wait?