Xavier Peña
Xavier Peña

Reputation: 7909

execute some function at certain hour in .NET

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

Answers (2)

ɐsɹǝʌ ǝɔıʌ
ɐsɹǝʌ ǝɔıʌ

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

Thomas Levesque
Thomas Levesque

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

Related Questions