SQL Server 2000数据库管理员 (DBA)Visual Studio .NET 2003SQL Server 2005中级开发Visual StudioSQL ServerSQLJavascriptWindowsVisual Basic
基于 Web 的作业调度程序






3.65/5 (24投票s)
一个完整的 VB.NET 应用程序,用于在线调度 DOS 命令任务
引言
在 Web 服务器上调度任务的方法有很多。 例如,您可以使用 Windows 任务计划程序和 SQL Server Agent。 此应用程序的独特之处在于您可以
- 使用 Web 浏览器调度作业
- 扩展调度应用程序以包含您自己的功能
Using the Code
此应用程序有三个组件
- 一个 Windows 服务,它将运行一个作业(DOS 命令文本)
- 一个 Web 应用程序,它将让您调度作业
- MS SQL Server 数据库存储过程,用于获取需要运行的作业列表
作业和调度信息存储在 MS SQL Server 数据库中。 Web 应用程序允许您使用私有或共享调度程序创建一个作业。 共享调度程序使调度作业更易于管理。 调度程序支持七种调度类型
类型 | 示例 |
每小时 | 每小时运行一次调度 |
每日 | 几天后运行作业 |
每周 | 在以下工作日运行作业(星期一、星期二等) |
每周跳过 | 在以下工作日运行作业(星期一或星期二),每隔一周跳过一次 |
周数 | 在以下工作日运行作业(星期一或星期二); 每月第二周在以下月份(一月、二月) |
日历 | 在以下日期运行作业(1日、2日 和当月的最后一天); 在以下月份(一月、二月) |
运行一次 |
每种调度类型都支持一个具有开始时间和结束时间的时间窗口。
以下是数据库的实体关系图
Windows 服务有一个每分钟触发一次的计时器。 该事件调用 GetJobsToRun
存储过程,该过程列出需要运行的作业。 每次作业运行时,都会更新 LastStatus
和 LastRunTime
。 此外,JobHistory
表保留每次作业运行的历史记录。
以下是 GetJobsToRun
存储过程的代码
CREATE PROCEDURE GetJobsToRun
AS
SELECT JobId, JobType, JobName, CommandText
FROM Job
WHERE JobId in (
SELECT j.JobId
FROM Schedule s
INNER JOIN Job j ON s.ScheduleId = j.ScheduleId
WHERE s.ScheduleType = 'Hourly'
and GetDate() between DATEADD(Hour, s.StartHour,
DATEADD(minute, s.StartMin, s.StartDate))
and Coalesce(s.EndDate,'12/12/2078')
and (j.LastRunTime is null
or DATEDIFF(minute, j.LastRunTime, GetDate()) >=
(EveryHour*60) + EveryMinute)
UNION
SELECT j.JobId
FROM Schedule s
INNER JOIN Job j ON s.ScheduleId = j.ScheduleId
WHERE s.ScheduleType = 'Daily'
and GetDate() between s.StartDate and Coalesce(s.EndDate,'12/12/2078')
and (j.LastRunTime is null or
DATEDIFF(Day, j.LastRunTime, GetDate()) > s.RepeatDays)
and (s.StartHour*60) + s.StartMin =
(DatePart(hour,GetDate())*60) + DatePart(minute,GetDate())
UNION
SELECT j.JobId
FROM Schedule s
INNER JOIN Job j ON s.ScheduleId = j.ScheduleId
INNER JOIN ScheduleWeek w ON w.ScheduleId = j.ScheduleId
WHERE s.ScheduleType = 'Weekly'
and GetDate() between s.StartDate and Coalesce(s.EndDate,'12/12/2078')
and DATEPART (weekday , GetDate()) = w.WeekDayId
and ((s.StartHour*60) + s.StartMin) <=
(DatePart(hour,GetDate())*60) + DatePart(minute,GetDate())
and (j.LastRunTime is null
or DATEDIFF(Day, j.LastRunTime, GetDate()) > 0)
UNION
SELECT j.JobId
FROM Schedule s
INNER JOIN Job j ON s.ScheduleId = j.ScheduleId
INNER JOIN ScheduleWeek w ON w.ScheduleId = j.ScheduleId
WHERE s.ScheduleType = 'WeeklySkip'
and GetDate() between s.StartDate and Coalesce(s.EndDate,'12/12/2078')
and DATEPART (weekday , GetDate()) = w.WeekDayId
and DATEDIFF(week, j.LastRunTime, GetDate()) >= s.RepeatWeeks
and ((s.StartHour*60) + s.StartMin) <=
(DatePart(hour,GetDate())*60) + DatePart(minute,GetDate())
and (j.LastRunTime is null
or DATEDIFF(Day, j.LastRunTime, GetDate()) > 0)
UNION
SELECT j.JobId
FROM Schedule s
INNER JOIN Job j ON s.ScheduleId = j.ScheduleId
INNER JOIN ScheduleWeek w ON w.ScheduleId = j.ScheduleId
INNER JOIN ScheduleMonth m ON m.ScheduleId = j.ScheduleId
WHERE s.ScheduleType = 'WeekNumber'
and GetDate() between s.StartDate and Coalesce(s.EndDate,'12/12/2078')
and w.WeekDayId = DATEPART (weekday , GetDate())
and m.MonthId = DATEPART (month , GetDate())
and s.WeekOfMonth =
(datepart(ww,GetDate())) + 1 -
datepart(ww,dateadd(dd,-(datepart(dd,GetDate())-1),GetDate()))
and ((s.StartHour*60) + s.StartMin) <=
(DatePart(hour,GetDate())*60) + DatePart(minute,GetDate())
and (j.LastRunTime is null
or DATEDIFF(Day, j.LastRunTime, GetDate()) > 0)
UNION
SELECT j.JobId
FROM Schedule s
INNER JOIN Job j ON s.ScheduleId = j.ScheduleId
INNER JOIN ScheduleMonth m ON m.ScheduleId = j.ScheduleId
INNER JOIN ScheduleDay d ON d.ScheduleId = j.ScheduleId
WHERE s.ScheduleType = 'Calendar'
and GetDate() between s.StartDate and Coalesce(s.EndDate,'12/12/2078')
and DATEPART (month , GetDate()) = m.MonthId
and (DATEPART (day , GetDate()) = d.DayId
or (d.DayId = 32 and
DAY(DATEADD(d, -DAY(DATEADD(m,1,GetDate())),DATEADD(m,1,GetDate())))
= DATEPART(day ,GetDate()))
)
and ((s.StartHour*60) + s.StartMin) <=
(DatePart(hour,GetDate())*60) + DatePart(minute,GetDate())
and (j.LastRunTime is null or DATEDIFF(Day, j.LastRunTime, GetDate()) > 0)
UNION
SELECT j.JobId
FROM Schedule s
INNER JOIN Job j ON s.ScheduleId = j.ScheduleId
WHERE s.ScheduleType = 'Once'
and GetDate() between s.StartDate and Coalesce(s.EndDate,'12/12/2078')
and ((s.StartHour*60) + s.StartMin) <=
(DatePart(hour,GetDate())*60) + DatePart(minute,GetDate())
and (j.LastRunTime is null) -- run once
)
以下是 RunDosCommand
函数的代码
Function RunDosCommand(ByVal sCommandText As String, _
Optional ByVal iTimeOutSec As Integer = 1) As String
Dim iPos As Integer = sCommandText.IndexOf(" ")
Dim sFileName As String
Dim sArguments As String = ""
If iPos = -1 Then
sFileName = sCommandText
Else
sFileName = sCommandText.Substring(0, iPos)
sArguments = sCommandText.Substring(iPos + 1)
End If
Dim sRet As String
Dim oProcess As Process = New Process
oProcess.StartInfo.UseShellExecute = False
oProcess.StartInfo.RedirectStandardOutput = True
oProcess.StartInfo.FileName = sFileName
oProcess.StartInfo.Arguments = sArguments
oProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
oProcess.StartInfo.CreateNoWindow = True
oProcess.Start()
oProcess.WaitForExit(1000 * iTimeOutSec)
If Not oProcess.HasExited Then
oProcess.Kill()
Return "Timeout"
End If
sRet = oProcess.StandardOutput.ReadToEnd()
If oProcess.ExitCode <> 0 And sRet = "" Then
sRet = "ExitCode: " & oProcess.ExitCode
End If
oProcess.Close()
Return sRet
End Function
从 dynarch.com 使用免费的第三方日历组件。
部署
以下是部署此应用程序的步骤
- 连接到 SQL Server 并创建一个名为
JobScheduler
的数据库。 - 向数据库添加一个将具有写入访问权限的用户。
- 打开 SQL 文件夹。 针对您的数据库运行 ScheduleSchema.sql。
- 针对您的数据库运行 GetJobsToRun.sql。
- 将 WebScheduler 文件夹复制到 C:\Inetpub\wwwroot\ 并将其设为虚拟目录。
- 双击 C:\Inetpub\wwwroot\WebScheduler\connect.udl 文件,将其指向
JobScheduler
数据库。 测试连接并单击“确定”。 - 将 WinJobService 文件夹复制到您的 programs 文件夹。
- 双击 <Programs Folder>\WinJobService\connect.udl 文件,将其指向
JobScheduler
数据库。 测试连接并单击 确定。 (您也可以将您在步骤 6 中创建的文件复制到此位置。) - 在 Microsoft Visual Studio .NET 2003 中打开
WinJobService
(WinJobService\WinJobService.sln) 项目并编译它。 - 通过运行服务注册脚本来注册服务器:WinJobService\bin\Install.vbs。 您可以稍后通过运行 Uninstall.vbs 来卸载该服务。