65.9K
CodeProject 正在变化。 阅读更多。
Home

基于 Web 的作业调度程序

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.65/5 (24投票s)

2007年5月11日

LGPL3

2分钟阅读

viewsIcon

153987

downloadIcon

4049

一个完整的 VB.NET 应用程序,用于在线调度 DOS 命令任务

引言

在 Web 服务器上调度任务的方法有很多。 例如,您可以使用 Windows 任务计划程序和 SQL Server Agent。 此应用程序的独特之处在于您可以

  • 使用 Web 浏览器调度作业
  • 扩展调度应用程序以包含您自己的功能

Using the Code

此应用程序有三个组件

  • 一个 Windows 服务,它将运行一个作业(DOS 命令文本)
  • 一个 Web 应用程序,它将让您调度作业
  • MS SQL Server 数据库存储过程,用于获取需要运行的作业列表

作业和调度信息存储在 MS SQL Server 数据库中。 Web 应用程序允许您使用私有或共享调度程序创建一个作业。 共享调度程序使调度作业更易于管理。 调度程序支持七种调度类型

类型 示例
每小时 每小时运行一次调度
每日 几天后运行作业
每周 在以下工作日运行作业(星期一、星期二等)
每周跳过 在以下工作日运行作业(星期一或星期二),每隔一周跳过一次
周数 在以下工作日运行作业(星期一或星期二); 每月第二周在以下月份(一月、二月)
日历 在以下日期运行作业(1、2 和当月的最后一天); 在以下月份(一月、二月)
运行一次  

每种调度类型都支持一个具有开始时间和结束时间的时间窗口。

Job Page.gif

以下是数据库的实体关系图

ERD

Windows 服务有一个每分钟触发一次的计时器。 该事件调用 GetJobsToRun 存储过程,该过程列出需要运行的作业。 每次作业运行时,都会更新 LastStatusLastRunTime。 此外,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 使用免费的第三方日历组件。

部署

以下是部署此应用程序的步骤

  1. 连接到 SQL Server 并创建一个名为 JobScheduler 的数据库。
  2. 向数据库添加一个将具有写入访问权限的用户。
  3. 打开 SQL 文件夹。 针对您的数据库运行 ScheduleSchema.sql
  4. 针对您的数据库运行 GetJobsToRun.sql
  5. WebScheduler 文件夹复制到 C:\Inetpub\wwwroot\ 并将其设为虚拟目录。
  6. 双击 C:\Inetpub\wwwroot\WebScheduler\connect.udl 文件,将其指向 JobScheduler 数据库。 测试连接并单击“确定”。
  7. WinJobService 文件夹复制到您的 programs 文件夹。
  8. 双击 <Programs Folder>\WinJobService\connect.udl 文件,将其指向 JobScheduler 数据库。 测试连接并单击 确定。 (您也可以将您在步骤 6 中创建的文件复制到此位置。)
  9. 在 Microsoft Visual Studio .NET 2003 中打开 WinJobService (WinJobService\WinJobService.sln) 项目并编译它。
  10. 通过运行服务注册脚本来注册服务器:WinJobService\bin\Install.vbs。 您可以稍后通过运行 Uninstall.vbs 来卸载该服务。
© . All rights reserved.