зеркало из https://github.com/dotnet/razor.git
125 строки
4.2 KiB
PowerShell
125 строки
4.2 KiB
PowerShell
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$ProcDumpPath,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]
|
|
$ProcDumpOutputPath,
|
|
[Parameter(Mandatory = $true)]
|
|
[datetime]
|
|
$WakeTime,
|
|
[Parameter(Mandatory = $true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string []]
|
|
$CandidateProcessNames
|
|
)
|
|
|
|
Write-Output "Setting up a scheduled job to capture process dumps.";
|
|
|
|
if ((-not (Test-Path $ProcDumpPath))) {
|
|
Write-Warning "Can't find ProcDump at '$ProcDumpPath'.";
|
|
}
|
|
else {
|
|
Write-Output "Using ProcDump from '$ProcDumpPath'.";
|
|
}
|
|
|
|
try {
|
|
$previousJobs = Get-Job -Name CaptureDumps* -ErrorAction SilentlyContinue;
|
|
$previousScheduledJobs = Get-ScheduledJob CaptureDumps* -ErrorAction SilentlyContinue;
|
|
|
|
if ($previousJobs.Count -ne 0) {
|
|
Write-Output "Found existing dump jobs.";
|
|
}
|
|
|
|
if ($previousScheduledJobs.Count -ne 0) {
|
|
Write-Output "Found existing dump jobs.";
|
|
}
|
|
|
|
$previousJobs | Stop-Job -PassThru | Remove-Job;
|
|
$previousScheduledJobs | Unregister-ScheduledJob;
|
|
}
|
|
catch {
|
|
Write-Output "There was an error cleaning up previous jobs.";
|
|
Write-Output $_.Exception.Message;
|
|
}
|
|
|
|
$repoRoot = Resolve-Path "$PSScriptRoot\..\..";
|
|
$ProcDumpOutputPath = Join-Path $repoRoot $ProcDumpOutputPath;
|
|
|
|
Write-Output "Dumps will be placed at '$ProcDumpOutputPath'.";
|
|
Write-Output "Watching processes $($CandidateProcessNames -join ', ')";
|
|
|
|
# This script registers as a scheduled job. This scheduled job executes after $WakeTime.
|
|
# When the scheduled job executes, it runs procdump on all alive processes whose name matches $CandidateProcessNames.
|
|
# The dumps are placed in $ProcDumpOutputPath
|
|
# If the build completes successfully in less than $WakeTime, a final step unregisters the job.
|
|
|
|
# Create a unique identifier for the job name
|
|
$JobName = "CaptureDumps" + (New-Guid).ToString("N");
|
|
|
|
# Ensure that the dumps output path exists.
|
|
if ((-not (Test-Path $ProcDumpOutputPath))) {
|
|
New-Item -ItemType Directory $ProcDumpOutputPath | Out-Null;
|
|
}
|
|
|
|
# We write a sentinel file that we use at the end of the build to
|
|
# find the job we started and to determine the results from the sheduled
|
|
# job (Whether it ran or not and to display the outputs form the job)
|
|
$sentinelFile = Join-Path $ProcDumpOutputPath "dump-sentinel.txt";
|
|
Out-File -FilePath $sentinelFile -InputObject $JobName | Out-Null;
|
|
|
|
[scriptblock] $ScriptCode = {
|
|
param(
|
|
$ProcDumpPath,
|
|
$ProcDumpOutputPath,
|
|
$CandidateProcessNames)
|
|
|
|
Write-Output "[$((Get-Date).ToLongTimeString())] Waking up to capture process dumps. Determining hanging processes.";
|
|
|
|
[System.Diagnostics.Process []]$AliveProcesses = @();
|
|
foreach ($candidate in $CandidateProcessNames) {
|
|
try {
|
|
$candidateProcesses = Get-Process $candidate 2>$null
|
|
$candidateProcesses | ForEach-Object { Write-Output "- Found candidate process '$candidate' with PID '$($_.Id)'." };
|
|
$AliveProcesses += $candidateProcesses;
|
|
}
|
|
catch {
|
|
Write-Output "No process found for $candidate";
|
|
}
|
|
}
|
|
|
|
Write-Output "Starting process dump capture.";
|
|
|
|
$dumpFullPath = [System.IO.Path]::Combine($ProcDumpOutputPath, "hung_PROCESSNAME_PID_YYMMDD_HHMMSS.dmp");
|
|
|
|
Write-Output "Capturing output for $($AliveProcesses.Length) processes.";
|
|
|
|
foreach ($process in $AliveProcesses) {
|
|
|
|
$procDumpArgs = @("-accepteula", "-ma", $process.Id, $dumpFullPath);
|
|
try {
|
|
Write-Output "Capturing dump for dump for '$($process.Name)' with PID '$($process.Id)'.";
|
|
Start-Process -FilePath $ProcDumpPath -ArgumentList $procDumpArgs -WindowStyle Hidden -Wait;
|
|
}
|
|
catch {
|
|
Write-Output "There was an error capturing a process dump for '$($process.Name)' with PID '$($process.Id)'."
|
|
Write-Warning $_.Exception.Message;
|
|
}
|
|
}
|
|
|
|
Write-Output "Done capturing process dumps.";
|
|
}
|
|
|
|
$ScriptTrigger = New-JobTrigger -Once -At $WakeTime;
|
|
|
|
try {
|
|
Register-ScheduledJob -Name $JobName -ScriptBlock $ScriptCode -Trigger $ScriptTrigger -ArgumentList $ProcDumpPath, $ProcDumpOutputPath, $CandidateProcessNames;
|
|
Write-Output "[$((Get-Date).ToLongTimeString())] Job scheduled to capture process dumps at $($WakeTime.ToLongTimeString())";
|
|
}
|
|
catch {
|
|
Write-Warning "Failed to register scheduled job '$JobName'. Dumps will not be captured for build hangs.";
|
|
Write-Warning $_.Exception.Message;
|
|
}
|