背景:Microsoft Azure;Windows Server 2012 R2。
我在 Scheduler 中有少量任务。在“设置”选项卡中,所有任务均标记为“如果任务已在运行,则适用以下规则:‘不启动新实例’”。
几天内这种情况都没问题。然后,调度程序似乎会在某项任务正在运行时启动每项任务的新实例。这些实例显示在任务管理器中已运行任务的旁边,但标记为“已暂停”。
这似乎是系统不稳定的普遍迹象。此行为出现后不久,SQL Server 就开始出现异常。
我正在编写一个维护脚本(这也必须使用调度程序,这真是太可惜了),它将计算生产应用程序的实例,如果内存中有多个应用程序(一个正在运行,一个已暂停),它将向开发团队发送一条短信。这是短期的解决方法。长期修复会更好。
有没有人遇到过类似的事情?如果遇到过,如何解决?
回应建议
我可以放
var currProcName = Process.GetCurrentProcess().ProcessName;
if (Process.GetProcessesByName(currProcName).Length > 1)
{
Warn($"An instance of {currProcName} is already running. Only one instance of this application is allowed.");
return;
}
或将其等效项添加到所有 EXE 中。但是,在当前设置中,这永远不会发出警告,因为 EXE 的第二个实例不会以此方式运行,而是在任务管理器中显示为“已暂停”。
允许调度程序启动一项作业(无论它是否已经在运行),并要求 EXE 本身确定它是否应该运行,这似乎有点低效,因为它要求每个 EXE 启动并可能每分钟死亡,而不是允许调度程序确定是否需要启动。
大约有 20 个任务被安排,有些每分钟一次,有些每 5 分钟一次,有些每 60 分钟一次。
对评论 #1 中问题的回复
问:您使用任务计划程序具体运行了什么,例如批处理脚本、exe 文件、PowerShell 脚本还是其他?
答:仅限 EXE,例如
<Actions Context="Author">
<Exec>
<Command>Handler.exe</Command>
<WorkingDirectory>C:\Web\Project</WorkingDirectory>
</Exec>
</Actions>
问:如何在调度程序选项中设置任务?
答:XML 文件的示例设置:
<Settings>
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
<AllowHardTerminate>true</AllowHardTerminate>
<StartWhenAvailable>true</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>true</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT1H</ExecutionTimeLimit>
<Priority>7</Priority>
</Settings>
XML 文件中的触发器示例
<Triggers>
<CalendarTrigger>
<Repetition>
<Interval>PT1M</Interval>
<Duration>P1D</Duration>
<StopAtDurationEnd>false</StopAtDurationEnd>
</Repetition>
<StartBoundary>2016-03-09T14:20:00</StartBoundary>
<ExecutionTimeLimit>PT30M</ExecutionTimeLimit>
<Enabled>true</Enabled>
<ScheduleByDay>
<DaysInterval>1</DaysInterval>
</ScheduleByDay>
</CalendarTrigger>
</Triggers>
对评论 #2 中问题的回复
问:您是否禁用然后又启用了这些任务?
答:应用更新时,会定期禁用并重新启用这些任务。
问:任务是从 XML 文件导入的吗?
答:原始任务(在另一台服务器上)是使用 GUI 创建的。结果被导出为 XML,移动到当前服务器,进行编辑和导入。
问:如果重新创建任务,问题能解决吗?
答:不是。
问:任务是否以退出代码终止?
答:如果您的意思是“任务是否以 Environment.Exit(n) 终止?”,那么答案是肯定的。但是,由于任务被定义为 EXE,而不是更大 CMD 的一部分,因此不会检查该值。
问:当新任务预计开始时,计划任务是否可能恰好终止?
答:我该如何证实这一点呢?
问:同时运行的同一任务的两个实例可以解释您所看到的不稳定性吗?
答:我不确定我是否理解了这个问题。我们绝不允许两个实例同时运行。目前的情况是,Windows 在其自行选择的时间允许一个实例运行,并允许另一个实例运行但处于“挂起”模式。有趣的是,我们目前的经验是挂起的任务无法终止。只有正在运行的任务才能终止。
答案1
任务计划程序和空闲条件
似乎有两种配置方法任务计划程序关于的工作空闲条件。
如果
StopOnIdleEnd
设置为真的,那么RestartOnIdle
应该是真的如果期望的结果是终止并重新启动任务。循环空闲状态
如果计算机在空闲状态之间循环,您可以使用以下空闲条件终止并重新启动任务。
要终止并重新启动任务,属性和元素都必须设置为 True:
示例配置
<IdleSettings> <StopOnIdleEnd>true</StopOnIdleEnd> <RestartOnIdle>true</RestartOnIdle> </IdleSettings>
这两个都应该设置为真的。
如果期望的结果是不要让任务在空闲状态下停止运行,那么你需要确保空闲时重启和空闲结束时停止设置为错误的。
示例配置
<IdleSettings> <StopOnIdleEnd>false</StopOnIdleEnd> <RestartOnIdle>false</RestartOnIdle> </IdleSettings>
这两个都应该设置为错误的。
答案2
我对您的问题的看法是,它是由以下行引起的:
<StopOnIdleEnd>true</StopOnIdleEnd>
以下是我对您的情景的理论推测:
- 进程在内核调用中处于等待状态,在此状态下无法停止。
- 计算机进入空闲状态然后退出。
- 任务计划程序尝试停止该进程,但只能将其暂停在僵尸状态(停止但无法终止)。
- 该任务被标记为终止,任务计划程序已启动一个新任务。
- 由于原始任务可能处于 SQL 事务的中间并且可能仍然持有锁,因此 SQL 数据库的行为受到损害。
解决方案应该是设置StopOnIdleEnd
为false
。没有理由因为计算机进入空闲状态而终止任务,无论时间多么短暂。事实上,粗暴地停止任何连接到 SQL 服务器的任务是一个非常糟糕的想法,因为它会让正在进行的事务未完成甚至无法回滚。