Time management of background jobs. Time output, if not completed in x seconds,

I would like my background jobs to (start with start-job

) and time them out after x

seconds. I find it difficult, however, to keep track of the running time on each individual job (I am running aprox 400 jobs).

I wish there was a way to disable the job and set it to failed

if not completed

in X seconds, but I couldn't find the timeout parameter.

What would be a good way to track individual assignment times?

I guess I could create a hash table with each job start time and job id and check the status running

and do a manual timeout, but that sounds like reinventing the wheel. Any ideas?

Edit Thanks everyone for the fruitful discussion and great inspiration on this topic!


source to share

4 answers

You can use a timer hash table:

 $jobtimer = @{}

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


The execution time of each job will be in $ jobtimer [$ job] .elapsed



Just go through the list of jobs in progress and stop any that missed your timeout, for example:

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

By the way, there are more properties for the job object than shown by the default formatting, for example:

3> $ job | fl *

State: Running
HasMoreData: True
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
PSJobType: BackgroundJob
Output: {}
Error: {}
Progress: {}
Verbose: {}
Debug: {}
Warning: {}


You can specify a timeout parameter Wait-Job



Specifies the maximum time to wait for each background job in seconds. By default, -1, it waits for the job to complete, no matter how long the runs. Time starts when you send a Wait-Job Command, not a Start-Job Command.

If this time is exceeded, the wait ends and the command line is returned even if the job is still running. No error messages are displayed.

Here's some sample code:

This part just does a few test tasks:

Remove-Job -Name *
$jobs = @()
1..10 | % {
    $jobs += Start-Job -ScriptBlock {
        Start-Sleep -Seconds (Get-Random -Minimum 5 -Maximum 20)


The variable $timedOutJobs

contains the given dates. Then you can restart them or whatever you have.

$jobs | Wait-Job -Timeout 10 
$timedOutJobs = Get-Job | ? {$_.State -eq 'Running'} | Stop-Job -PassThru




For completeness, the answer includes the maximum number of seconds per job and the maximum number of concurrent jobs. Like this is what most people are after.

The following example retrieves the printer configuration for each print server. There may be over 3000 printers, so we added regulation.

$i = 0
$maxConcurrentJobs = 40
$maxSecondsPerJob = 60
$jobTimer = @{ }

$StopLongRunningJobs = {
    $jobTimer.GetEnumerator().where( {
            ($_.Value.IsRunning) -and
            ($_.Value.Elapsed.TotalSeconds -ge $maxSecondsPerJob)
        }).Foreach( {
            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)

        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




All Articles