Executing Code with a Timeout (Part 1)

by Dec 5, 2018

If you’d like to make sure some code won’t execute forever, you can use background jobs to implement a timeout. Here is a sample function:

function Invoke-CodeWithTimeout
{
    param
    (
        [Parameter(Mandatory)]
        [ScriptBlock]
        $Code,

        [int]
        $Timeout = 5

    )

    $j = Start-Job -ScriptBlock $Code
    $completed = Wait-Job $j -Timeout $Timeout
    if ($completed -eq $null)
    {
      throw "Job timed out."
      Stop-Job -Job $j
    }
    else
    {
      Receive-Job -Job $j
    }
    Remove-Job -Job $j
}

So basically, to run some code with a maximum timeout of 5 seconds, try this:

 
PS> Invoke-CodeWithTimeout -Code { Start-Sleep -Seconds 6; Get-Date } -Timeout 5
Job timed out.
At line:18 char:7
+       throw "Job timed out."
+       ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (Job timed out.:String) [], RuntimeException
    + FullyQualifiedErrorId : Job timed out.
 

PS> Invoke-CodeWithTimeout -Code { Start-Sleep -Seconds 3; Get-Date } -Timeout 5

Thursday November 1, 2018 14:53:26 
 

The approach works; however, it has a considerable overhead related to the jobs it uses. The overhead of creating background jobs and returning the data to your foreground task may add to the overall time. Which is why we are looking at a better approach in tomorrow’s tip.

Twitter This Tip! ReTweet this Tip!