Reputation: 7909
This post and many others propose the Windows Task Scheduler instead, but for various reasons this is not an option for me.
So I have the piece of code shown below, which works fairly well (it has been operative for months now). But I still have a few doubts which grind my soul, since the rest of my systems are based on this code:
I feel this subject is a bit too complex given my skills, so I could really use some fresh ideas.
Public CHECK_INTERVAL_IN_MILLISECONDS As Integer = 1000 '1 second
''' <summary>
''' Initializes the timer that will work as a check interval
''' </summary>
Private Sub initializeTimer()
_timer = New Timer(CHECK_INTERVAL_IN_MILLISECONDS)
AddHandler _timer.Elapsed, New ElapsedEventHandler(AddressOf checkScheduledItems)
_timer.Enabled = True
End Sub
''' <summary>
''' The items are timed at HH:mm and executed every N minutes.
''' For example, I could make an item be scheduled at 01:00 every 12*60 minutes and it would be executed at 1am and at 1pm every day.
''' </summary>
Public Sub checkScheduledItems(ByVal timeMarginInMilliseconds As Double)
'NOTE: timeMarginInMilliseconds = CHECK_INTERVAL_IN_MILLISECONDS
Dim currentTime As Date = Now
Dim exporterScheduleList = executionSchedule.getAllActiveItemsByPriority
Dim hourSpan As Integer = 48
'First deal with fixed dates:
For Each executionScheduledItem As ExecutionSchedule In exporterScheduleList.Values
If executionScheduledItem.active Then
Dim baseExecTime As Date = executionScheduledItem.createBaseDate(currentTime)
Dim execFrequencyInMinutes As Integer = executionScheduledItem.scheduled_frequency
For minuteInterval As Integer = 0 To hourSpan * 60 Step execFrequencyInMinutes
Dim execTime As Date = baseExecTime.AddMinutes(minuteInterval)
Dim timeDiff = currentTime.Subtract(execTime).TotalMilliseconds
If timeDiff >= 0 And timeDiff < timeMarginInMilliseconds Then
Dim newExecutionWaitlistItem As ExecutionWaitlist = New ExecutionWaitlist(executionScheduledItem)
newExecutionWaitlistItem.save()
Exit For 'stop checking the minute interval
End If
Next
End If
Next
End Sub
''' <summary>
''' Gets the scheduled_time (a string with format "HH:mm") and transforms it into a Date with -24h.
''' </summary>
Public Function createBaseDate(ByVal currentTime As Date) As Date
Dim scheduled_time As String = Me.scheduled_time
Dim scheduled_time_vector() As String = scheduled_time.Split(":")
Dim baseExecTime = New Date(currentTime.Year, currentTime.Month, currentTime.Day, scheduled_time_vector(0), scheduled_time_vector(1), 0)
baseExecTime.AddHours(-24)
Return baseExecTime
End Function
Upvotes: 1
Views: 5652
Reputation: 4512
If Task Scheduler is not an option you could create a Windows Service Application which will be executed every minute.
Imports System.Timers
Private Timer As System.Threading.Timer = Nothing
Private ProcessRunning As Boolean = False
Protected Overrides Sub OnStart(ByVal args() As String)
ProcessRunning = False
Timer = New System.Threading.Timer(New Threading.TimerCallback(AddressOf Timer_Elapsed), Nothing, 0, 60000)
End Sub
Private Sub Timer_Elapsed(ByVal sender As Object)
If Not ProcessRunning Then Execute()
End Sub
Once executed, you could check the time to trigger your code
Private Sub Execute()
If DateTime.Now.ToString("hh:mm") = "12:00" Then
'Call your function
ProcessRunning = False
End If
End Sub
Upvotes: 0
Reputation: 292465
Is it really the only option I have inside a .NET code to trigger scheduled functions, as all the other posts suggest? It looks a bit like patchwork to me.
You can use a third-party scheduler library. Quartz.NET is pretty good.
Does it have a certain probability of skipped elements? I mean: with execution times etc, I think it can occur that the interval of 1 second in which the time check is performed is somehow skipped.
If the task you perform every second takes more than one second, you won't miss "ticks" (not with System.Timers.Timer, at least), but you can end up creating an awful lot of threads, which can kill your app performance and eventually make it run out of memory.
Is there any better way to work around the "frequency in minutes" part? Setting the baseDate has me a bit confused... besides, it only seems to work if the hour is set as close to 00:00 as possible (for example: for some reason "18:00 every 12h" won't execute at 6am with the current code)
Not sure about that, but it goes to show that it's not a simple problem you're trying to solve; you should definitely use an existing library, rather than reinventing the wheel.
Upvotes: 1