Guard against multiple run invocations

This commit is contained in:
Matt Parker
2025-08-08 00:29:50 +10:00
parent 995449c6d1
commit 8f0dd5c1cf

View File

@@ -1,4 +1,5 @@
using System.Diagnostics; using System.Collections.Concurrent;
using System.Diagnostics;
using Ardalis.GuardClauses; using Ardalis.GuardClauses;
using AsyncReadProcess.Common; using AsyncReadProcess.Common;
using AsyncReadProcess; using AsyncReadProcess;
@@ -9,14 +10,18 @@ namespace SharpIDE.Application.Features.Run;
public class RunService public class RunService
{ {
public HashSet<SharpIdeProjectModel> RunningProjects { get; } = []; private readonly ConcurrentDictionary<SharpIdeProjectModel, SemaphoreSlim> _projectLocks = [];
// TODO: optimise this Copilot junk
public async Task RunProject(SharpIdeProjectModel project) public async Task RunProject(SharpIdeProjectModel project)
{ {
Guard.Against.Null(project, nameof(project)); Guard.Against.Null(project, nameof(project));
Guard.Against.NullOrWhiteSpace(project.FilePath, nameof(project.FilePath), "Project file path cannot be null or empty."); Guard.Against.NullOrWhiteSpace(project.FilePath, nameof(project.FilePath), "Project file path cannot be null or empty.");
await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding); await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);
var semaphoreSlim = _projectLocks.GetOrAdd(project, new SemaphoreSlim(1, 1));
var waitResult = await semaphoreSlim.WaitAsync(0);
if (waitResult is false) throw new InvalidOperationException($"Project {project.Name} is already running.");
try
{
var processStartInfo = new ProcessStartInfo2 var processStartInfo = new ProcessStartInfo2
{ {
FileName = "dotnet", FileName = "dotnet",
@@ -49,4 +54,9 @@ public class RunService
Console.WriteLine("Project ran successfully."); Console.WriteLine("Project ran successfully.");
} }
finally
{
semaphoreSlim.Release();
}
}
} }