我有一个要求,我需要杀死\停止主要任务,如果它已经运行了很长时间。我正在考虑创建一个后台作业来监视时间并在超时后用正确的消息杀死主要作业,但我不知道该怎么做。
像这样的东西......
function Kill-MainTask{
$sb = {
Start-Sleep -Seconds 5
throw "main task should end"
}
$job1 = Start-Job -ScriptBlock $sb
Write-Host "main task running"
Start-Sleep -Seconds 10
#This statement should not run
Write-Host "main task not finished"
}
Kill-MainTask
当我调用Kill-MainTask函数时,它应该打印“mian task running”但是应该在5秒后抛出。
现有几个示例显示了如何使用此主要和子作业监视用例。请参阅以下示例和资源链接。
Monitoring the Progress of a PowerShell Job
Quick Tip To Find Out What Your Background Jobs Are Doing
例:
这是一个简单的脚本,可以创建5个后台作业(由$ Num定义)。提交后,我们将开始监控工作进度。我们将$ TotProg定义为0以启动,然后查询StatusDescription-
并且因为这返回一个数组,我们只想要最后一个元素,因此-1元素引用 - 并将它添加到我们的$ TotProg。之后我们检查$ TotProg是否大于0(否则你会得到除零错误),显示我们的进度条,等待几秒钟然后再循环。继续运行代码(不要在ISE中单步执行,真正看到我的意思,你必须运行它)。
$Num = 5
$Jobs = @()
ForEach ($Job in (1..$Num))
{ $Jobs += Start-Job -ScriptBlock {
$Count = 1
Do {
Write-Progress -Id 2 -Activity "Background Job" -Status $Count -PercentComplete 1
$Count ++
Start-Sleep -Seconds 4
} Until ($Count -gt 5)
}
}
$Total = $Num * 5
Write-Progress -Id 1 -Activity "Watching Background Jobs" -Status "Waiting for background jobs to started" -PercentComplete 0
Do {
$TotProg = 0
ForEach ($Job in $Jobs)
{ Try {
$Info =
$TotProg += ($Job | Get-Job).ChildJobs[0].Progress.StatusDescription[-1]
}
Catch {
Start-Sleep -Seconds 3
Continue
}
}
If ($TotProg)
{ Write-Progress -Id 1 -Activity "Watching Background Jobs" -Status "Waiting for background jobs to complete: $TotProg of $Total" -PercentComplete (($TotProg / $Total) * 100)
}
Start-Sleep -Seconds 3
} Until (($Jobs | Where State -eq "Running").Count -eq 0)
$Jobs | Remove-Job -Force
Write-Progress -Id 1 -Activity "Watching Background Jobs" -Status "Completed! $Total of $Total" -PercentComplete 100
Start-Sleep -Seconds 1
Write-Progress -Id 1 -Activity "Watching Background Jobs" -Status "Completed! $Total of $Total" -Completed
或者这种方法
Creating A Timeout Feature In Your PowerShell Scripts
# define a timeout
$Timeout = 10 ## seconds
# Code for the scriptblock
$jobs = Get-Job
$Condition = {param($jobs) 'Running' -notin $jobs.State }
$ConditionArgs = $jobs
# define how long in between checks
$RetryInterval = 5
# Start the timer
$timer = [Diagnostics.Stopwatch]::StartNew()
# Invoke code actions
while (($timer.Elapsed.TotalSeconds -lt $Timeout) -and (& $Condition $ConditionArgs)) {
## Wait a specific interval
Start-Sleep -Seconds $RetryInterval
## Check the time
$totalSecs = [math]::Round($timer.Elapsed.TotalSeconds,0)
Write-Verbose -Message "Still waiting for action to complete after [$totalSecs] seconds..."
}
# The action either completed or timed out. Stop the timer.
$timer.Stop()
# Return status of what happened
if ($timer.Elapsed.TotalSeconds -gt $Timeout)
{ throw 'Action did not complete before timeout period.' }
else
{ Write-Verbose -Message 'Action completed before the timeout period.' }