From bd00b716a838c77dae20dc64f3ae171552fcf897 Mon Sep 17 00:00:00 2001 From: "Christopher H. Laco" Date: Wed, 29 Oct 2008 23:38:10 -0400 Subject: [PATCH] Reworked from Timers.Timer to Threading.Timer --- Siphon/Monitors/DataMonitor.vb | 68 ++++++++++++++++--------- SiphonTests/MonitorTests.vb | 22 +++----- SiphonTests/Processors/MockProcessor.vb | 6 +-- SiphonTests/app.config | 2 +- 4 files changed, 57 insertions(+), 41 deletions(-) diff --git a/Siphon/Monitors/DataMonitor.vb b/Siphon/Monitors/DataMonitor.vb index f29c6a9..f00b8eb 100644 --- a/Siphon/Monitors/DataMonitor.vb +++ b/Siphon/Monitors/DataMonitor.vb @@ -1,4 +1,5 @@ Imports System.Collections.ObjectModel +Imports System.Threading Imports System.Timers Imports log4net @@ -15,7 +16,8 @@ Public MustInherit Class DataMonitor Private _processing As Boolean = False Private _processor As IDataProcessor = Nothing Private _schedule As IMonitorSchedule = Nothing - Private WithEvents _timer As System.Timers.Timer + Private _eventWaitHandle As EventWaitHandle = New ManualResetEvent(False) + Private _timer As Threading.Timer = Nothing ''' ''' Creates a new DataMonitor instance. @@ -85,8 +87,7 @@ Public MustInherit Class DataMonitor Public Overridable Sub Start() Implements IDataMonitor.Start Log.InfoFormat("Starting Monitor {0}", Me.Name) - Timer.Interval = Me.NextInterval - Timer.Start() + Me.Timer.Change(Me.GetNextInterval, Timeout.Infinite) End Sub ''' @@ -96,7 +97,7 @@ Public MustInherit Class DataMonitor Public Overridable Sub Pause() Implements IDataMonitor.Pause Log.InfoFormat("Pausing Monitor {0}", Me.Name) - Timer.Stop() + Me.Timer.Change(Timeout.Infinite, Timeout.Infinite) End Sub ''' @@ -106,8 +107,7 @@ Public MustInherit Class DataMonitor Public Overridable Sub [Resume]() Implements IDataMonitor.Resume Log.InfoFormat("Resuming Monitor {0}", Me.Name) - Timer.Interval = Me.NextInterval - Timer.Start() + Me.Timer.Change(Me.GetNextInterval, Timeout.Infinite) End Sub ''' @@ -115,28 +115,37 @@ Public MustInherit Class DataMonitor ''' ''' Public Overridable Sub [Stop]() Implements IDataMonitor.Stop - If Timer.Enabled Then - Log.InfoFormat("Stopping Monitor {0}", Me.Name) + Log.InfoFormat("Stopping Monitor {0}", Me.Name) - If Me.Processing Then - Log.Debug("Waiting for processor to finish") - End If - - Timer.Stop() + If Me.Processing Then + Log.Debug("Waiting for processot to finish") + Me.EventWaitHandle.WaitOne() + Log.Debug("Done waiting for processor to finish") End If End Sub + ''' + ''' Returns the internal event wait handle used for timer thread sync. + ''' + ''' + ''' EventWaitHandle + ''' + Protected Overridable ReadOnly Property EventWaitHandle() As EventWaitHandle + Get + Return _eventWaitHandle + End Get + End Property + ''' ''' Returns the internal timer used for the current monitor. ''' ''' ''' Timer ''' - Protected Overridable ReadOnly Property Timer() As Timer + Protected Overridable ReadOnly Property Timer() As Threading.Timer Get If _timer Is Nothing Then - _timer = New Timer - _timer.AutoReset = False + _timer = New Threading.Timer(New TimerCallback(AddressOf Me.OnTimerElapsed), Me, Timeout.Infinite, Timeout.Infinite) End If Return _timer @@ -183,11 +192,11 @@ Public MustInherit Class DataMonitor End Sub ''' - ''' Gets the next event from the schedule and sets the timers interval. + ''' Gets the next event from the schedule and returns the next interval in milliseconds to be sent to the timer. ''' - ''' + ''' Integer. The number of milliseconds to wait until scanning for new data. ''' - Private Function NextInterval() As Integer + Protected Overridable Function GetNextInterval() As Integer Dim start As DateTime = DateTime.Now Dim nextEvent As DateTime = Me.Schedule.NextEvent(start) Dim interval As Integer = (nextEvent - start).TotalMilliseconds @@ -199,23 +208,36 @@ Public MustInherit Class DataMonitor Return interval End Function - Private Sub _timer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles _timer.Elapsed + ''' + ''' Subroutine called when the timer time has elapsed. + ''' + ''' + ''' + Protected Overridable Sub OnTimerElapsed(ByVal state As Object) + Log.Debug("Timer Elapsed") Me.Pause() Try Dim items As Collection(Of Object) = Me.Scan + Log.DebugFormat("Scan returned {0} items", items.Count) + If items.Count > 0 Then + Log.DebugFormat("Pre Process Processing {0}", _processing) + _processing = True - Log.DebugFormat("{0} {1}", Me.Name, _processing) + For Each item As Object In items Me.Processor.Process(item) Next - Log.Debug("POST Process") _processing = False + + Log.DebugFormat("Post Process Processing {0}", _processing) End If Catch ex As Exception - 'Log.Debug("BOOM", ex) + Log.Error("Exception", ex) + Finally + _eventWaitHandle.Set() End Try Me.Resume() diff --git a/SiphonTests/MonitorTests.vb b/SiphonTests/MonitorTests.vb index d0c08e9..09dff91 100644 --- a/SiphonTests/MonitorTests.vb +++ b/SiphonTests/MonitorTests.vb @@ -28,8 +28,6 @@ Public Class MonitorTests End Using End Using End Using - - tempdir.Delete(True) End Sub _ @@ -48,8 +46,6 @@ Public Class MonitorTests End Using End Using End Using - - tempdir.Delete(True) End Sub _ @@ -68,8 +64,6 @@ Public Class MonitorTests End Using End Using End Using - - tempdir.Delete(True) End Sub _ @@ -89,8 +83,6 @@ Public Class MonitorTests End Using End Using End Using - - Directory.Delete(tempdir, True) End Sub _ @@ -112,8 +104,6 @@ Public Class MonitorTests End Using End Using End Using - - tempdir.Delete(True) End Sub @@ -122,20 +112,24 @@ Public Class MonitorTests Dim tempdir As DirectoryInfo = Directory.CreateDirectory(Path.Combine(Path.GetTempPath, Path.GetRandomFileName)) File.Create(Path.Combine(tempdir.FullName, "SUCCESS")) - Using schedule = New DailySchedule(DateTime.Now.AddSeconds(2).TimeOfDay) + 'Using schedule = New DailySchedule(DateTime.Now.AddSeconds(2).TimeOfDay) + Using schedule = New IntervalSchedule(2) Using processor = New MockProcessor - Using monitor As IDataMonitor = New LocalDirectoryMonitor("LocalMonitor", tempdir.FullName, schedule, processor) + Using monitor As LocalDirectoryMonitor = New LocalDirectoryMonitor("LocalMonitor", tempdir.FullName, schedule, processor) processor.DelayProcess = 10 monitor.Start() Threading.Thread.Sleep(3000) + + Assert.IsTrue(monitor.Processing, "Processing is true when a worker processor is still running") + Dim pre As DateTime = DateTime.Now monitor.Stop() + Dim post As DateTime = DateTime.Now Assert.AreEqual(1, processor.Count, "Has processed 1 files") + Assert.GreaterOrEqual((post - pre).TotalSeconds, 5, "Waited for still running process to finish") End Using End Using End Using - - tempdir.Delete(True) End Sub #End Region diff --git a/SiphonTests/Processors/MockProcessor.vb b/SiphonTests/Processors/MockProcessor.vb index d978e50..170a224 100644 --- a/SiphonTests/Processors/MockProcessor.vb +++ b/SiphonTests/Processors/MockProcessor.vb @@ -16,9 +16,9 @@ Public Class MockProcessor Dim info As FileInfo = New FileInfo(data) - Log.DebugFormat("Delay process {0}", Me.DelayProcess) - - Log.DebugFormat("Delay process {0}", Me.DelayProcess) + Log.DebugFormat("MockProccessor Process Start Delay {0}", Me.DelayProcess) + Threading.Thread.Sleep(Me.DelayProcess * 1000) + Log.DebugFormat("MockProccessor Process Finished Delay {0}", Me.DelayProcess) Select Case info.Name.ToUpper Case "SUCCESS" diff --git a/SiphonTests/app.config b/SiphonTests/app.config index 640f3a9..15fb7f1 100644 --- a/SiphonTests/app.config +++ b/SiphonTests/app.config @@ -6,7 +6,7 @@ - +