Powershell 管理后台作业的运行时间。如果x秒后未完成超时,
我想给我的后台作业计时(从Powershell 管理后台作业的运行时间。如果x秒后未完成超时,,powershell,timeout,start-job,Powershell,Timeout,Start Job,我想给我的后台作业计时(从start job开始),并在x秒后超时。然而,我发现很难跟踪每个单独作业的运行时间(我正在运行大约400个作业) 我希望有一种方法可以使作业超时,并将其设置为失败(如果在X秒内未完成),但我没有找到超时参数 跟踪作业的单个运行时间的好方法是什么 我想我可以创建一个包含每个作业的开始时间和作业id的哈希表,对照运行状态检查并手动超时,但这听起来有点像“发明轮子”。 有什么想法吗 编辑 感谢大家就这个话题进行了富有成效的讨论,并给予了巨大的启发 您可以指定等待作业的超时选
start job
开始),并在x
秒后超时。然而,我发现很难跟踪每个单独作业的运行时间(我正在运行大约400个作业)
我希望有一种方法可以使作业超时,并将其设置为失败
(如果在X秒内未完成
),但我没有找到超时参数
跟踪作业的单个运行时间的好方法是什么
我想我可以创建一个包含每个作业的开始时间和作业id的哈希表,对照运行状态检查并手动超时,但这听起来有点像“发明轮子”。
有什么想法吗
编辑
感谢大家就这个话题进行了富有成效的讨论,并给予了巨大的启发 您可以指定等待作业的超时选项:
-超时
确定每个后台作业的最大等待时间(秒)。
默认值,-1将等待作业完成,无论作业完成多长时间
跑。当您提交Wait Job命令而不是
启动作业命令
如果超过此时间,则等待结束,并显示命令提示
返回,即使作业仍在运行。未显示任何错误消息
显示
下面是一些示例代码:
这部分只是做了一些测试工作:
Remove-Job -Name *
$jobs = @()
1..10 | % {
$jobs += Start-Job -ScriptBlock {
Start-Sleep -Seconds (Get-Random -Minimum 5 -Maximum 20)
}
}
变量$timedOutJobs
包含超时的作业。然后,您可以重新启动它们或您所拥有的一切
$jobs | Wait-Job -Timeout 10
$timedOutJobs = Get-Job | ? {$_.State -eq 'Running'} | Stop-Job -PassThru
只需浏览正在运行的作业列表,并停止任何超过超时规格的作业,例如:
$timeout = [timespan]::FromMinutes(1)
$now = Get-Date
Get-Job | Where {$_.State -eq 'Running' -and
(($now - $_.PSBeginTime) -gt $timeout)} | Stop-Job
$timeout=[timespan]::FromMinutes(1)
$now=获取日期
获取作业|其中{$\.State-eq'Running'-和
($now-$\PSBeginTime)-gt$timeout)}停止作业
顺便说一句,作业对象的属性比默认格式显示的更多,例如:
3 > $job | fl *
State : Running
HasMoreData : True
StatusMessage :
Location : localhost
Command : Start-sleep -sec 30
JobStateInfo : Running
Finished : System.Threading.ManualResetEvent
InstanceId : de370ea8-763b-4f3b-ba0e-d45f402c8bc4
Id : 3
Name : Job3
ChildJobs : {Job4}
PSBeginTime : 3/18/2012 11:07:20 AM
PSEndTime :
PSJobType : BackgroundJob
Output : {}
Error : {}
Progress : {}
Verbose : {}
Debug : {}
Warning : {}
3>$job | fl*
状态:正在运行
哈斯莫尔数据:对
状态信息:
位置:本地主机
命令:开始睡眠-第30秒
JobStateInfo:正在运行
完成:System.Threading.ManualResetEvent
实例ID:de370ea8-763b-4f3b-ba0e-d45f402c8bc4
身份证号码:3
姓名:Job3
子作业:{Job4}
PSBeginTime:3/18/2012 11:07:20上午
PSEndTime:
PSJobType:背景作业
输出:{}
错误:{}
进展:{}
详细:{}
调试:{}
警告:{}
您可以使用计时器的哈希表:
$jobtimer = @{}
foreach ($job in $jobs){
start-job -name $job -ScriptBlock {scriptblock commands}
$jobtimer[$job] = [System.Diagnostics.Stopwatch]::startnew()
}
每个作业的运行时间将以$jobtimer[$job]为单位。已用时间为完整性起见,此答案结合了每个作业的最大秒数和运行的最大并发作业数。因为这是大多数人追求的
下面的示例检索每个打印服务器的打印机配置。可以有3000多台打印机,所以我们增加了节流功能
$i = 0
$maxConcurrentJobs = 40
$maxSecondsPerJob = 60
$jobTimer = @{ }
$StopLongRunningJobs = {
$jobTimer.GetEnumerator().where( {
($_.Value.IsRunning) -and
($_.Value.Elapsed.TotalSeconds -ge $maxSecondsPerJob)
}).Foreach( {
$_.Value.Stop()
Write-Verbose "Stop job '$($_.Name.Name)' that ran for '$($_.Value.Elapsed.TotalSeconds)' seconds"
Stop-Job $_.Name
})
}
Foreach ($Computer in @($GetPrinterJobResults.Where( { $_.Data }) )) {
foreach ($Printer in $Computer.Data) {
do {
& $StopLongRunningJobs
$running = @(Get-Job -State Running)
$Wait = $running.Count -ge $maxConcurrentJobs
if ($Wait) {
Write-Verbose 'Waiting for jobs to fininsh'
$null = $running | Wait-Job -Any -Timeout 5
}
} while ($Wait)
$i++
Write-Verbose "$I $($Computer.ComputerName) Get print config '$($Printer.Name)'"
$Job = $Printer | Get-PrintConfiguration -AsJob -EA Ignore
$jobtimer[$Job] = [System.Diagnostics.Stopwatch]::StartNew()
}
}
$JobResult = Get-Job | Wait-Job -Timeout $maxSecondsPerJob -EA Ignore
$JobResult = Get-Job | Receive-Job -EA Ignore
$JobResult.count
我可能会想出类似您在上一段中提到的哈希表解决方案。似乎是个好主意。Psbegintime正是我要找的!但是我找不到它。您正在运行V2还是V3?目前正在运行V3。如果V2没有该字段,那么是的,只需创建一个哈希表,将$job对象(或id)映射到创建作业时创建的时间戳。我在Win8 beta(PSv3)上,而且我似乎也没有Ps*属性:/(Start job-ScriptBlock{gp}gm-MemberType属性Ps*)。Count
是0
.Hmm,我想我只能说,希望这个属性能进入最终版本。:-)Windows 7上的Powershell Beta 3中也没有PSBegintime。祈祷这会进入国际泳联:)这也是我的第一个想法,但等待工作的一个问题是它被阻塞了。如果脚本可以在OP的400个作业完成或超时时被完全阻止,那么这将起作用。在使用等待作业超时时,还有一个隐含的假设,即所有作业或多或少都在同一时间开始。@KeithHill Sune在SO的帮助下开发了这个脚本。lol。前面的一个问题涉及如何限制作业。我不认为400将同时运行。你是对的@AndyArismendi!我正在扼杀工作。。当时只跑了20英里(我发现这是一个不错的甜蜜点)。如果我在脚本末尾(或脚本中的任何位置)执行等待作业,脚本将重新提交所有超时的作业。。我需要把这个限制在油门水平。我想我必须对foreach循环中的哈希表进行测试。无论如何,谢谢:):)@Sune如果您将$timedOutJobs
制作为一个数组,并将其添加到您运行的每组作业中,您可以使用此方法来完成此任务。假设您运行20并收集阵列中该块的超时作业,然后再运行20并收集阵列中该块的超时作业。最后,您将拥有一个包含所有超时作业的数组。这将给所有作业同等的超时时间。或者,只需重新提交第一个作业。因此,如果你保持20次运行,并且有一个按时间顺序排列的作业列表。然后,当等待超时时,您可以停止并重新提交一个作业(列表中第一个作业,即运行时间最长的作业)。这非常完美。但是,我在直接引用值而不将其设置为变量时遇到问题。。为什么get job | foreach{echo$jobtimer[$\.name].appeased.totalseconds}
不起作用,但$jobtimer[4]。appeased.totalseconds
起作用?