タスクが完了するまで特定の時間間隔で実行し続ける「ハートビート」を持つタスクを実行したいと思います。
このような拡張メソッドがうまくいくと思います:
public static async Task WithHeartbeat(this Task primaryTask, TimeSpan heartbeatInterval, Action<CancellationToken> heartbeatAction, CancellationToken cancellationToken)
例えば:
public class Program {
public static void Main() {
var cancelTokenSource = new CancellationTokenSource();
var cancelToken = cancelTokenSource.Token;
var longRunningTask = Task.Factory.StartNew(SomeLongRunningTask, cancelToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
var withHeartbeatTask = longRunningTask.WithHeartbeat(TimeSpan.FromSeconds(1), PerformHeartbeat, cancelToken);
withHeartbeatTask.Wait();
Console.WriteLine("Long running task completed!");
Console.ReadLine()
}
private static void SomeLongRunningTask() {
Console.WriteLine("Starting long task");
Thread.Sleep(TimeSpan.FromSeconds(9.5));
}
private static int _heartbeatCount = 0;
private static void PerformHeartbeat(CancellationToken cancellationToken) {
Console.WriteLine("Heartbeat {0}", ++_heartbeatCount);
}
}
このプログラムは次を出力するはずです。
Starting long task
Heartbeat 1
Heartbeat 2
Heartbeat 3
Heartbeat 4
Heartbeat 5
Heartbeat 6
Heartbeat 7
Heartbeat 8
Heartbeat 9
Long running task completed!
ハートビートは最初のタイムアウト (つまり 1 秒) 後に開始されるため、(通常の状況では) "Heartbeat 10" を出力しないことに注意してください。同様に、タスクにかかる時間がハートビート間隔より短い場合、ハートビートはまったく発生しません。
これを実装する良い方法は何ですか?
背景情報: Azure Service Busキューをリッスンするサービスがあります。処理が完了するまでメッセージを完了させたくありません(キューから完全に削除されます)。これには、メッセージの最大LockDurationである 5 分よりも長い時間がかかる可能性があります。したがって、このハートビート アプローチを使用して、ロック期間が終了する前にRenewLockAsyncを呼び出す必要があります。これにより、長時間の処理が行われている間にメッセージがタイムアウトにならなくなります。