I improved Ivan Leonenko answer by including a new parameter, which queue calls to you callback if the period is less than the callback run time. And replaced the legacy TimerCallback with an action. And finally, use our cancel token in the last delay, and used ConfigureAwait to increase concurrency, as the callback can be executed on any thread.
internal sealed class Timer : CancellationTokenSource
{
internal Timer(Action