Управление временем выполнения фоновых заданий. Тайм-аут, если он не завершен через x секунд, - PullRequest
5 голосов
/ 18 марта 2012

Я хотел бы рассчитать время моих фоновых заданий (началось с start-job) и установить время ожидания после x секунд. Однако мне трудно отслеживать время выполнения каждого отдельного задания (я запускаю приблизительно 400 заданий).

Хотелось бы, чтобы был способ тайм-аута задания и установил его на failed, если не completed через X секунд, но я не нахожу параметр времени ожидания.

Каким будет хороший способ отслеживать время выполнения заданий?

Полагаю, я мог бы создать хеш-таблицу с временем начала каждой работы и идентификатором задания, проверить состояние running и выполнить тайм-аут вручную, но это звучит как "изобретать колесо". Есть идеи?

Редактировать Спасибо всем за плодотворное обсуждение и большое вдохновение на эту тему!

Ответы [ 4 ]

5 голосов
/ 18 марта 2012

Вы можете использовать хеш-таблицу таймеров:

 $jobtimer = @{}

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

Время выполнения каждого задания будет в $ jobtimer [$ job] .elapsed

4 голосов
/ 18 марта 2012

Просто пройдите по списку запущенных заданий и остановите все, которые выполнялись после вашей спецификации тайм-аута, например ::10000

$timeout = [timespan]::FromMinutes(1)
$now = Get-Date
Get-Job | Where {$_.State -eq 'Running' -and 
                 (($now - $_.PSBeginTime) -gt $timeout)} | Stop-Job

Кстати, у объекта задания больше свойств, чем показано по умолчанию, например ::1004*

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       : {}
2 голосов
/ 18 марта 2012

Вы можете указать время ожидания Wait-Job:

-Timeout

Определяет максимальное время ожидания для каждого фонового задания в секундах. Значение по умолчанию -1 ожидает завершения задания независимо от его продолжительности пробеги. Время начинается, когда вы отправляете команду Wait-Job, а не Команда Пуск-Задание.

Если это время превышено, ожидание заканчивается и командная строка возвращается, даже если задание все еще выполняется. Нет сообщения об ошибке отображается.

* * 1010

Вот пример кода:

Эта часть просто выполняет несколько тестовых заданий:

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
0 голосов
/ 16 июля 2019

Для полноты этого ответа объединяются максимальное количество секунд на одно задание и максимальное число одновременных выполняемых заданий.Это то, что нужно большинству людей.

В приведенном ниже примере извлекается конфигурация принтера для каждого сервера печати.Принтеров может быть более 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
...