Reputation: 22074
I have a parallel build of multiple projects, each one of those at some point in time does invoke <Exec />
task. This exec task is running 3pty tool that crashes if there is another instance of this tool running. Is there some native way how to implement "mutex" in msbuild ?
The obvious solution (that works) is to make the build synchronous - but that is slowing down the whole build.
Upvotes: 6
Views: 205
Reputation: 22074
In the end I ended up writing my own msbuild extension library like below
msbuild part:
<UsingTask TaskName="MutexExec" AssemblyFile="$(CommonTasksAssembly)" />
C# part:
// <PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.9.0" />
// <PackageReference Include="Microsoft.Build.Tasks.Core" Version="16.9.0" />
// <PackageReference Include="Microsoft.Build.Framework" Version="16.9.0" />
using System;
using System.Diagnostics;
using System.Threading;
using Microsoft.Build.Framework;
using Microsoft.Build.Tasks;
/// <summary>
/// Like a Exec task, but with critical section
/// </summary>
public class MutexExec : Exec
{
/// <summary>
/// Gets or sets mutex name
/// </summary>
[Required]
public string MutexName { get; set; }
/// <inheritdoc />
public override bool Execute()
{
var timeout = TimeSpan.FromMinutes(5);
var stopwatch = Stopwatch.StartNew();
while (stopwatch.Elapsed < timeout)
{
bool createdNew;
using (var mutex = new Mutex(true, this.MutexName, out createdNew))
{
if (createdNew)
{
bool result = base.Execute();
try
{
this.Log.LogMessage(MessageImportance.Normal, "Releasing {0}", this.MutexName);
mutex.ReleaseMutex();
}
catch (Exception e)
{
this.Log.LogError("Failure releasing {0} - {1}", this.MutexName, e);
}
return result;
}
}
this.Log.LogMessage(MessageImportance.Normal, "Waiting for {0} - ellapsed {1}", this.MutexName, stopwatch.Elapsed);
Thread.Sleep(5000);
continue;
}
this.Log.LogError("Failed to acquire {0} in {1}.", this.MutexName, timeout);
return false;
}
}
Upvotes: 2