需要一个定时器在特定时间触发,每 5 分钟触发一次,直到工作完成
Need A Timer To Fire At Specific Time And Every 5 Minutes Until Job Complete
我需要帮助为我的应用程序设置特定类型的计时器。我的场景是这样的:
我想在一天中的特定时间 运行 计时器(比如 4:00AM)。然后该计时器执行许多不同的事件,每个事件都会触发并从数据库中获取数据并进行处理(使用后台工作程序)。所有不同的事件需要不同的时间才能完成(可能是 30 秒,也可能是 5 分钟)。我想每 5 分钟连续输入一次计时器事件,然后检查所有事件是否已完成。如果是这样,请停止计时器并在第二天早上 4:00AM 重新启动它,依此类推。
所以这个过程看起来像这样:
04:00AM - 启动计时器并启动后台工作程序
04:05AM - 再次检查进程是否已完成(如果已完成,则停止计时器)
04:10AM - 再次检查进程是否已完成(如果已完成,则停止计时器)
等等....
我已经有了处理我的数据库信息的后台工作程序代码。所以我只需要设置计时器的帮助。
到目前为止,我的 Tick
活动中有以下内容:
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
感谢任何帮助。
您可以从以下基本框架开始:
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
与其每秒触发计时器并检查当前时间(无论如何这似乎有问题),为什么不计算凌晨 4 点之前的毫秒数并将计时器设置为在该时间触发?
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
如果您希望计时器在 5 分钟后再次启动,您可以执行类似的操作。我会将定时器的 AutoReset
属性 设置为 False
并在设置间隔后每次调用 Start
。
我需要帮助为我的应用程序设置特定类型的计时器。我的场景是这样的:
我想在一天中的特定时间 运行 计时器(比如 4:00AM)。然后该计时器执行许多不同的事件,每个事件都会触发并从数据库中获取数据并进行处理(使用后台工作程序)。所有不同的事件需要不同的时间才能完成(可能是 30 秒,也可能是 5 分钟)。我想每 5 分钟连续输入一次计时器事件,然后检查所有事件是否已完成。如果是这样,请停止计时器并在第二天早上 4:00AM 重新启动它,依此类推。
所以这个过程看起来像这样:
04:00AM - 启动计时器并启动后台工作程序
04:05AM - 再次检查进程是否已完成(如果已完成,则停止计时器)
04:10AM - 再次检查进程是否已完成(如果已完成,则停止计时器)
等等....
我已经有了处理我的数据库信息的后台工作程序代码。所以我只需要设置计时器的帮助。
到目前为止,我的 Tick
活动中有以下内容:
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
感谢任何帮助。
您可以从以下基本框架开始:
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
与其每秒触发计时器并检查当前时间(无论如何这似乎有问题),为什么不计算凌晨 4 点之前的毫秒数并将计时器设置为在该时间触发?
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
如果您希望计时器在 5 分钟后再次启动,您可以执行类似的操作。我会将定时器的 AutoReset
属性 设置为 False
并在设置间隔后每次调用 Start
。