タイトルにあるとおり、VB11.0(.NET Framework 4.5+Visual Studio 2012)が対象です。
概要
メイン処理が実行中かどうかを監視。想定時間内に終わらない場合は警告処理します。
アイデア
- メイン処理と並行して監視をする必要があるので、非同期の処理が必要
→ Asyncで対応する。 - メイン処理が終わったら監視をする必要がないので、メイン処理終了判定が必要
→ Using(IDisposable)で判定する。 - 警告処理
→ NLogを使う。
使い方
Private logger As NLog.Logger
Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles Me.Load
Me.logger = NLog.LogManager.GetCurrentClassLogger
End Sub
Private Sub ExecuteButton_Click(sender As Object, e As EventArgs) Handles ExecuteButton.Click
'5秒で終了する予定。終わらない場合、警告。
'以降、3秒おきにチェック。終わっていない場合、警告。
'遅延時間が30秒をを超えると致命的例外。
Using w As New ProcessWatcher With {.ExpectTime = New TimeSpan(0, 0, 5),
.WatchSpan = New TimeSpan(0, 0, 3),
.MaxDelayTime = New TimeSpan(0, 0, 30)}
'メイン処理
logger.Info("Start")
'遅延をメッセージボックスを使って擬似的に起こします
MessageBox.Show("本当に実行しますか?")
logger.Info("End")
End Using
End Sub
ProcessWatcher が監視クラスです。同クラスが有効な期間(Using)が指定された時間に終わらないと警告、もしくは致命的例外がでます。
ProcessWatcherクラス
Public Sub New()
Me.WatchingAsync()
End Sub
Private Async Sub WatchingAsync()
Dim past As TimeSpan = TimeSpan.Zero
Try
Await Task.Run(
Async Function()
Do While True
If past.Equals(TimeSpan.Zero) Then
Await Task.Delay(Me.ExpectTime.TotalMilliseconds)
past = past.Add(Me.ExpectTime)
Else
Await Task.Delay(Me.WatchSpan.TotalMilliseconds)
past = past.Add(Me.WatchSpan)
End If
'廃棄されているなら正常終了
If Me.disposedValue Then Return
'メッセージの組み立て
Dim delay = past.Add(-Me.ExpectTime)
Dim msg As String = String.Empty
If delay.Equals(TimeSpan.Zero) Then
msg = String.Format("{0}経過", past.ToString("hh\:mm\:ss"))
Else
msg = String.Format("{0}経過({1}遅延)", past.ToString("hh\:mm\:ss"), delay.ToString("hh\:mm\:ss"))
End If
'遅延の上限値を超えた場合、致命的エラーを出して監視をやめる
If Me.WatchSpan.Equals(TimeSpan.Zero) OrElse Me.MaxDelayTime <= delay Then
msg &= ControlChars.NewLine & "遅延時間の閾値を超えました。監視を中止します。"
Throw New InvalidOperationException(msg)
End If
'遅延状況を警告で出力
logger.Warn(msg)
Loop
End Function)
Catch ex As Exception
logger.Fatal(ex.Message, ex)
End Try
End Sub
プロパティやIDisposableの実装部分は省略しています。 やってることは非常に単純で、コンストラクタで非同期で監視処理をコールしているだけ。
備考
自分自身で実行かつ監視しているので、そもそも起動していない可能性を監視することはできません。当たり前ですけど。
また、中止するのは「監視処理」のみで、「メイン処理」を止めることはできません。