【问题标题】:How do I kill main\parent task through background job?如何通过后台作业杀死主\父任务?
【发布时间】:2019-04-23 19:19:55
【问题描述】:

我有一个要求,如果它已经运行了很长时间,我需要杀死\停止主任务。我正在考虑创建一个后台作业来监控时间并在超时后通过适当的消息终止主要作业,但我不知道该怎么做。

像这样..

    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 秒后应该抛出。

【问题讨论】:

  • $job1 永远不会被调用。您将信息分配给变量,但从不在任何地方使用它。
  • 这是我的问题,我该如何使用这些信息?我的主要工作是做很多事情,如果需要超过 5 秒,我想正确地杀死主要工作。
  • 你可以翻转它。你有你的初始脚本调用Start-Job $MainTask,然后,因为它有 Job 对象,你可以检查它是否在 5 秒内完成。既然你有 Job 对象,那么你也可以杀死它。
  • 我无法真正翻转,因为在主任务运行时,我需要在控制台上向用户显示输出。如果我将其作为作业运行,我将无法显示进度,这不是一个选项。

标签: powershell parallel-processing background jobs


【解决方案1】:

现有的几个示例展示了如何使用这个主要和子作业监控用例。请参阅以下示例和资源链接。

Monitoring the Progress of a PowerShell Job

Quick Tip To Find Out What Your Background Jobs Are Doing

例子:

这是一个创建 5 个后台作业的简单脚本(如 由 $Num 定义)。提交后,我们将开始监控 工作的进展。我们定义 $TotProg 为 0 开始,然后查询 状态描述——

并且由于这返回一个数组,我们只想要 最后一个元素,因此是 -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.'  }

【讨论】:

    猜你喜欢
    • 2021-11-22
    • 2019-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-22
    相关资源
    最近更新 更多