7

我想为我的后台作业计时(以 开头)并在几秒钟start-job后将它们超时。x但是,我发现很难跟踪每个单独作业的运行时间(我正在运行大约 400 个作业)。

我希望有一种方法可以让工作超时并将其设置为failed如果不是completed在 X 秒内,但我发现没有超时参数。

跟踪作业的各个运行时间的好方法是什么?

我想我可以创建一个包含每个作业的开始时间和作业 ID 的哈希表,并检查running状态并进行手动超时,但这听起来有点“发明轮子”。有任何想法吗?

编辑 感谢大家就这个话题进行了富有成果的讨论和极大的启发!

4

4 回答 4

7

您可以使用计时器的哈希表:

 $jobtimer = @{}

 foreach ($job in $jobs){
   start-job -name $job -ScriptBlock {scriptblock commands}
   $jobtimer[$job] = [System.Diagnostics.Stopwatch]::startnew()
   }

每个作业的运行时间将在 $jobtimer[$job].elapsed

于 2012-03-18T18:23:04.403 回答
4

只需浏览正在运行的作业列表并停止任何超过您的超时规范的作业,例如:

$timeout = [时间跨度]::FromMinutes(1)
$now = 获取日期
找工作 | 其中 {$_.State -eq 'Running' -and
                 (($now - $_.PSBeginTime) -gt $timeout)} | 停工

顺便说一句,作业对象的属性比默认格式显示的要多,例如:

3 > $工作 | 佛罗里达*


状态:运行
有更多数据:真
状态消息 :
位置:本地主机
命令:开始睡眠-sec 30
JobStateInfo : 正在运行
完成:System.Threading.ManualResetEvent
InstanceId : de370ea8-763b-4f3b-ba0e-d45f402c8bc4
编号:3
姓名:工作3
ChildJobs:{Job4}
PSBeginTime : 3/18/2012 11:07:20 AM
PS结束时间:
PSJobType : 背景作业
输出 : {}
错误 : {}
进步 : {}
详细:{}
调试:{}
警告 : {}
于 2012-03-18T17:15:47.233 回答
2

您可以指定超时选项Wait-Job

-超时

确定每个后台作业的最长等待时间,以秒为单位。默认值 -1 等待作业完成,无论它运行多长时间。当您提交 Wait-Job 命令而不是 Start-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
于 2012-03-18T09:24:50.907 回答
0

为了完整起见,此答案结合了每个作业的最大秒数和运行的最大并发作业。因为这是大多数人所追求的。

下面的示例检索每个打印服务器的打印机配置。可以有超过 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
于 2019-07-16T09:28:08.170 回答