Skip to content

Commit 991aac0

Browse files
committed
Moved timeout management to the top process.
1 parent 167962e commit 991aac0

File tree

9 files changed

+59
-56
lines changed

9 files changed

+59
-56
lines changed

Build.ps1

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[CmdletBinding(PositionalBinding = $false)]
55
param(
66
[switch]$Interactive, # Opens an interactive PowerShell session
7-
[switch]$VsDebug, # Enable the remote debugger.
7+
[switch]$StartVsmon, # Enable the remote debugger.
88
[Parameter(ValueFromRemainingArguments)]
99
[string[]]$BuildArgs # Arguments passed to `Build.ps1` within the container.
1010
)
@@ -15,7 +15,7 @@ $EngPath = 'eng'
1515
$ProductName = 'PostSharpEngineering'
1616
####
1717

18-
if ( $VsDebug )
18+
if ( $StartVsmon )
1919
{
2020
$vsmonport = 4024
2121
Write-Host "Starting Visual Studio Remote Debugger, listening at port $vsmonport." -ForegroundColor Cyan
@@ -47,7 +47,7 @@ if ( -not $Interactive -or $BuildArgs )
4747
# Run the project.
4848
& dotnet run --project "$PSScriptRoot\$EngPath\src\Build$ProductName.csproj" -- $BuildArgs
4949

50-
if ($VsDebug)
50+
if ($StartVsmon)
5151
{
5252
Write-Host ""
5353
Write-Host "Killing vsmon.exe."

DockerBuild.ps1

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ param(
1212
[string]$ImageName, # Image name (defaults to a name based on the directory).
1313
[string]$BuildAgentPath = 'C:\BuildAgent',
1414
[switch]$LoadEnvFromKeyVault, # Forces loading environment variables form the key vault.
15-
[switch]$VsDebug, # Enable the remote debugger.
15+
[switch]$StartVsmon, # Enable the remote debugger.
1616
[Parameter(ValueFromRemainingArguments)]
1717
[string[]]$BuildArgs # Arguments passed to `Build.ps1` within the container.
1818
)
@@ -187,7 +187,7 @@ if (-not $NoNuGetCache)
187187
}
188188

189189
# Mount VS Remote Debugger
190-
if ($VsDebug)
190+
if ($StartVsmon)
191191
{
192192
if (-not $env:DevEnvDir)
193193
{
@@ -277,9 +277,9 @@ if (-not $BuildImage)
277277
Write-Host "Building the product in the container." -ForegroundColor Green
278278

279279
# Prepare Build.ps1 arguments
280-
if ($VsDebug)
280+
if ($StartVsmon)
281281
{
282-
$BuildArgs = @("-VsDebug") + $BuildArgs
282+
$BuildArgs = @("-StartVsmon") + $BuildArgs
283283
}
284284

285285
if ($Interactive)

src/PostSharp.Engineering.BuildTools/BaseCommand.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Linq;
1313
using System.Runtime.InteropServices;
1414
using System.Text.Json;
15+
using System.Threading;
1516

1617
namespace PostSharp.Engineering.BuildTools
1718
{
@@ -23,6 +24,8 @@ public abstract class BaseCommand<T> : Command<T>
2324
{
2425
public sealed override int Execute( CommandContext context, T settings )
2526
{
27+
CancellationTokenSource? timeoutCancellation = null;
28+
2629
try
2730
{
2831
var stopwatch = Stopwatch.StartNew();
@@ -42,6 +45,13 @@ public sealed override int Execute( CommandContext context, T settings )
4245
buildContext = buildContext.WithUseProjectDirectoryAsWorkingDirectory( true );
4346
}
4447

48+
// Sets up a timeout. The Timer class does not support long periods, so we use CancellationTokenSource.
49+
if ( settings.Timeout != null )
50+
{
51+
timeoutCancellation = new CancellationTokenSource( TimeSpan.FromMinutes( settings.Timeout.Value ) );
52+
timeoutCancellation.Token.Register( () => OnTimeout( buildContext, stopwatch ) );
53+
}
54+
4555
MSBuildHelper.InitializeLocator();
4656

4757
if ( buildContext.IsRunningUnderContainer )
@@ -152,8 +162,23 @@ public sealed override int Execute( CommandContext context, T settings )
152162

153163
return 10;
154164
}
165+
finally
166+
{
167+
timeoutCancellation?.Dispose();
168+
}
155169
}
156170

157171
protected abstract bool ExecuteCore( BuildContext context, T settings );
172+
173+
private static void OnTimeout( BuildContext buildContext, Stopwatch stopwatch )
174+
{
175+
// ReSharper disable AccessToModifiedClosure
176+
177+
buildContext.Console.WriteError( $"The process timed out after {stopwatch.Elapsed}. Dumping and killing the process tree." );
178+
var directory = Path.Combine( buildContext.RepoDirectory, buildContext.Product.DumpDirectory );
179+
ProcessHelper.DumpAndKillProcessTree( buildContext.Console, Process.GetCurrentProcess(), directory );
180+
181+
// ReSharper restore AccessToModifiedClosure
182+
}
158183
}
159184
}

src/PostSharp.Engineering.BuildTools/Build/BuildContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ internal TimeSpan BuildTimeout
185185
{
186186
get
187187
{
188-
var setting = (this.Settings as BuildSettings)?.Timeout;
188+
var setting = this.Settings.Timeout;
189189

190190
#pragma warning disable CS0618 // Type or member is obsolete
191191
return setting == null ? this.Product.BuildTimeout : TimeSpan.FromMinutes( setting.Value );

src/PostSharp.Engineering.BuildTools/Build/BuildSettings.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,6 @@ public int? SolutionId
179179
[CommandOption( "--user" )]
180180
public string UserName { get; set; } = Environment.GetEnvironmentVariable( EnvironmentVariableNames.EngUserName ) ?? Environment.UserName;
181181

182-
[Description( "Overrides the build timeout." )]
183-
[CommandOption( "--timeout" )]
184-
public int? Timeout { get; set; }
185-
186182
public BuildSettings WithIncludeTests( bool value )
187183
{
188184
var clone = (BuildSettings) this.MemberwiseClone();

src/PostSharp.Engineering.BuildTools/Build/Solutions/DotNetSolution.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ public override bool Restore( BuildContext context, BuildSettings settings )
3232
private string GetFinalSolutionPath( BuildContext context )
3333
=> FileSystemHelper.GetFinalPath( Path.Combine( context.RepoDirectory, this.SolutionPath ) );
3434

35-
private ToolInvocationOptions CreateInvocationOptions( BuildContext context )
36-
=> new( this.EnvironmentVariables ) { ExecutionTimeout = context.BuildTimeout, MinidumpDirectory = context.Product.DumpDirectory };
35+
private ToolInvocationOptions CreateInvocationOptions() => new( this.EnvironmentVariables );
3736

3837
private bool RunDotNet(
3938
BuildContext context,
@@ -48,7 +47,7 @@ private bool RunDotNet(
4847
command,
4948
arguments,
5049
addConfigurationFlag,
51-
this.CreateInvocationOptions( context ) );
50+
this.CreateInvocationOptions() );
5251

5352
private bool RunBuildOrTests(
5453
BuildContext context,
@@ -91,7 +90,7 @@ private bool RunBuildOrTests(
9190
args = "";
9291
}
9392

94-
var options = this.CreateInvocationOptions( context );
93+
var options = this.CreateInvocationOptions();
9594

9695
bool success;
9796

src/PostSharp.Engineering.BuildTools/CommonCommandSettings.cs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ protected virtual void AppendSettings( StringBuilder stringBuilder )
4141
{
4242
stringBuilder.Append( "--ci " );
4343
}
44+
45+
if ( this.Timeout != null )
46+
{
47+
stringBuilder.Append( $"--timeout {this.Timeout} " );
48+
}
4449
}
4550

4651
public override string ToString()
@@ -74,11 +79,11 @@ public override string ToString()
7479
[Description( "Simulate a continuous integration build by setting the build ContinuousIntegrationBuild property to TRUE." )]
7580
[CommandOption( "--ci" )]
7681
public bool SimulateContinuousIntegration { get; set; }
77-
82+
7883
[Description( "Use the project or solution directory as a working directory." )]
7984
[CommandOption( "--project-dir-as-working-dir" )]
8085
public bool UseProjectDirectoryAsWorkingDirectory { get; set; }
81-
86+
8287
[Description( "Use local dependencies instead of build server dependencies." )]
8388
[CommandOption( "--use-local-dependencies" )]
8489
public bool UseLocalDependencies { get; set; }
@@ -94,23 +99,26 @@ protected set
9499
this._unparsedProperties = value;
95100

96101
this.Properties = this.Properties.AddRange(
97-
value.Select(
98-
v =>
102+
value.Select( v =>
103+
{
104+
var split = v.Split( '=' );
105+
106+
if ( split.Length > 1 )
99107
{
100-
var split = v.Split( '=' );
101-
102-
if ( split.Length > 1 )
103-
{
104-
return new KeyValuePair<string, string>( split[0].Trim(), split[1].Trim() );
105-
}
106-
else
107-
{
108-
return new KeyValuePair<string, string>( split[0].Trim(), "True" );
109-
}
110-
} ) );
108+
return new KeyValuePair<string, string>( split[0].Trim(), split[1].Trim() );
109+
}
110+
else
111+
{
112+
return new KeyValuePair<string, string>( split[0].Trim(), "True" );
113+
}
114+
} ) );
111115
}
112116
}
113117

118+
[Description( "Overrides the build timeout." )]
119+
[CommandOption( "--timeout" )]
120+
public int? Timeout { get; set; }
121+
114122
public ImmutableDictionary<string, string> Properties { get; protected set; } =
115123
ImmutableDictionary.Create<string, string>( StringComparer.OrdinalIgnoreCase );
116124

src/PostSharp.Engineering.BuildTools/Utilities/ToolInvocationHelper.cs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -265,30 +265,9 @@ public static bool InvokeTool(
265265
}
266266

267267
Process process = new() { StartInfo = startInfo };
268-
var stopwatch = Stopwatch.StartNew();
269-
270-
// Sets up a timeout. The Timer class does not support long periods, so we use CancellationTokenSource.
271-
CancellationTokenSource? timeoutCancellation = null;
272-
273-
if ( options.ExecutionTimeout != null )
274-
{
275-
timeoutCancellation = new CancellationTokenSource( options.ExecutionTimeout.Value );
276-
timeoutCancellation.Token.Register( OnTimeout );
277-
278-
void OnTimeout()
279-
{
280-
// ReSharper disable AccessToModifiedClosure
281-
282-
console.WriteError( $"The process timed out after {stopwatch.Elapsed}. Dumping and killing the process tree." );
283-
ProcessHelper.DumpAndKillProcessTree( console, process, options.MinidumpDirectory );
284-
285-
// ReSharper restore AccessToModifiedClosure
286-
}
287-
}
288268

289269
using ( ManualResetEvent stdErrorClosed = new( false ) )
290270
using ( ManualResetEvent stdOutClosed = new( false ) )
291-
using ( timeoutCancellation )
292271
{
293272
// Filters process output where matching RegEx value indicates process failure.
294273
void FilterProcessOutput( string output )

src/PostSharp.Engineering.BuildTools/Utilities/ToolInvocationOptions.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ public record ToolInvocationOptions(
3434

3535
public TimeSpan OutputReadingTimeout { get; init; } = TimeSpan.FromSeconds( 10 );
3636

37-
public TimeSpan? ExecutionTimeout { get; init; }
38-
39-
public string? MinidumpDirectory { get; init; }
40-
4137
public static TimeSpan LongOutputReadingTimeout => TimeSpan.FromSeconds( 60 );
4238

4339
public ToolInvocationOptions WithEnvironmentVariables( ImmutableDictionary<string, string?> additionalEnvironmentVariables )

0 commit comments

Comments
 (0)