问题
I need help setting up a specific type of timer for my application. My scenario is this:
I want to run a timer at a specific time of day (say 4:00AM). That timer then executes a number of different events that each go off and grab data from a database and process it (using background workers). All the different events take different times to finish (could be 30 seconds, could be 5 minutes). I want to continuously enter the timer event every 5 minutes thereafter checking if all events have finished. If so, stop the timer and restart it again at 4:00AM the next morning and so on.
So the process would look like this:
04:00AM - Start Timer and initiate background workers
04:05AM - Check again to see if processes have completed (if so, stop timer)
04:10AM - Check again to see if processes have completed (if so, stop timer)
And so on....
I already have my background worker code that processes my database information. So I just need help setting up the timer.
So far I have the following in my Tick event:
Private Sub tmr_Maintenance_Tick(sender As Object, e As EventArgs) Handles tmr_Maintenance.Tick
Dim CurrentTime As Date
Dim CurrHour As Integer
CurrentTime = DateTime.Now
CurrHour = CurrentTime.Hour
'Automatic Sales Import
With My.Settings
If CurrHour = 4 Then
If Not .Maintenance_Ran Then
CreateLog("Maintenance Started")
If Not .Yesterdays_Sales_Imported Then
CreateLog("Importing Yesterday's Sales From Portal")
If Not YesterdaysSales_Worker.IsBusy Then YesterdaysSales_Worker.RunWorkerAsync()
End If
If Not .WTD_Sales_Imported Then
CreateLog("Importing Week To Date Sales From Portal")
If Not WeekToDateSales_Worker.IsBusy Then WeekToDateSales_Worker.RunWorkerAsync()
End If
If Not .LW_Sales_Imported Then
CreateLog("Importing Last Week Sales From Portal")
If Not LastWeekSales_Worker.IsBusy Then LastWeekSales_Worker.RunWorkerAsync()
End If
If .Yesterdays_Sales_Imported = True And .WTD_Sales_Imported = True And .LW_Sales_Imported = True Then
.Maintenance_Ran = True
End If
End If
Else
.Maintenance_Ran = False
End If
End With
My.Settings.Save()
End Sub
Any help appreciated thanks.
回答1:
Here's a basic framework you can start from:
Public Class Form1
Private Enum MaintenanceState
WaitingToStart
Started
End Enum
Private Target As DateTime
Private state As MaintenanceState = MaintenanceState.WaitingToStart
Private MaintenanceTime As New TimeSpan(4, 0, 0) ' 4:00 am
Private WaitingInterval As New TimeSpan(0, 5, 0) ' Five minutes
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Target = GetNextMaintenanceTarget(MaintenanceTime)
tmr_Maintenance.Interval = 1000
tmr_Maintenance.Start()
End Sub
Private Sub tmr_Maintenance_Tick(sender As Object, e As EventArgs) Handles tmr_Maintenance.Tick
' optionally display time remaining until next target
Dim ts As TimeSpan = Target.Subtract(DateTime.Now)
Label1.Text = ts.ToString("hh\:mm\:ss")
' see if we've hit the target
If DateTime.Now >= Target Then
tmr_Maintenance.Stop()
Select Case state
Case MaintenanceState.WaitingToStart
' ... start all the jobs ...
state = MaintenanceState.Started
Target = DateTime.Now.Add(WaitingInterval)
Case MaintenanceState.Started
' ... check to see if the jobs are all done ...
If Not AllJobsCompleted Then
Target = DateTime.Now.Add(WaitingInterval)
Else
state = MaintenanceState.WaitingToStart
Target = GetNextMaintenanceTarget(MaintenanceTime)
End If
End Select
tmr_Maintenance.Start()
End If
End Sub
Private Function GetNextMaintenanceTarget(ByVal time As TimeSpan) As DateTime
Dim dt As DateTime = DateTime.Today.Add(time)
If DateTime.Now > dt Then
dt = dt.AddDays(1) ' already past target time for today, next start is tomorrow
End If
Return dt
End Function
End Class
回答2:
Instead of firing your timer every second and checking the current hour (which seems problematic anyway) why not calculate how many milliseconds until 4 am and set the timer to fire at that time?
Dim timer = New Timer()
timer.Interval = MillisecondsUntilNextFourAm
...
Function MillisecondsUntilNextFourAm() As Integer
Dim now = DateTime.Now()
If now.Hour < 4 Then
Return (TimeSpan.FromHours(4) - now.TimeOfDay).TotalMilliseconds
Else
Return (TimeSpan.FromHours(28) - now.TimeOfDay).TotalMilliseconds
End If
End Function
You could do something similar if you then want the timer to fire again in 5 minutes. I would set the timer's AutoReset property to False and call Start each time after setting the interval.
来源:https://stackoverflow.com/questions/28441916/need-a-timer-to-fire-at-specific-time-and-every-5-minutes-until-job-complete