From 8093a22c3686de7182108c7189b7459cef32d783 Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 14 Jan 2021 02:36:33 -0800 Subject: [PATCH] Ensure watched projects are not built in parallel to avoid file locking issues --- .../Model/Application.cs | 15 +++++++++++++++ src/Microsoft.Tye.Hosting/ProcessRunner.cs | 19 +++++++++++++++++-- .../Watch/DotNetWatcher.cs | 5 +++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Tye.Hosting/Model/Application.cs b/src/Microsoft.Tye.Hosting/Model/Application.cs index 7430a0c3..a1b63fe8 100644 --- a/src/Microsoft.Tye.Hosting/Model/Application.cs +++ b/src/Microsoft.Tye.Hosting/Model/Application.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Threading; namespace Microsoft.Tye.Hosting.Model { @@ -17,6 +18,18 @@ namespace Microsoft.Tye.Hosting.Model Source = source.FullName; ContextDirectory = source.DirectoryName!; Services = services; + + foreach (var s in Services.Values) + { + if (s.Description.RunInfo is ProjectRunInfo projectRunInfo) + { + var projectFileName = projectRunInfo.ProjectFile.FullName; + if (!ProjectFileLocks.ContainsKey(projectFileName)) + { + ProjectFileLocks[projectFileName] = new SemaphoreSlim(1, 1); + } + } + } } public string Source { get; } @@ -25,6 +38,8 @@ namespace Microsoft.Tye.Hosting.Model public Dictionary Services { get; } + internal Dictionary ProjectFileLocks { get; } = new Dictionary(); + public Dictionary Items { get; } = new Dictionary(); public string? Network { get; set; } diff --git a/src/Microsoft.Tye.Hosting/ProcessRunner.cs b/src/Microsoft.Tye.Hosting/ProcessRunner.cs index 706cfadc..a912b686 100644 --- a/src/Microsoft.Tye.Hosting/ProcessRunner.cs +++ b/src/Microsoft.Tye.Hosting/ProcessRunner.cs @@ -359,9 +359,24 @@ namespace Microsoft.Tye.Hosting }, Build = async () => { - if (service.Description.RunInfo is ProjectRunInfo) + if (service.Description.RunInfo is ProjectRunInfo projectRunInfo) { - var buildResult = await ProcessUtil.RunAsync("dotnet", $"build \"{service.Status.ProjectFilePath}\" /nologo", throwOnError: false, workingDirectory: application.ContextDirectory); + ProcessResult buildResult; + + var projectFile = projectRunInfo.ProjectFile.FullName; + var projectSemaphore = application.ProjectFileLocks[projectFile]; + await projectSemaphore.WaitAsync(); + try + { + _logger.LogDebug($"[{replica}] Building project {projectFile}:"); + buildResult = await ProcessUtil.RunAsync("dotnet", $"build \"{service.Status.ProjectFilePath}\" /nologo", throwOnError: false, workingDirectory: application.ContextDirectory); + } + finally + { + _logger.LogDebug($"[{replica}] Finished Building project {projectFile}:"); + projectSemaphore.Release(); + } + if (buildResult.ExitCode != 0) { _logger.LogInformation("Building projects failed with exit code {ExitCode}: \r\n" + buildResult.StandardOutput, buildResult.ExitCode); diff --git a/src/Microsoft.Tye.Hosting/Watch/DotNetWatcher.cs b/src/Microsoft.Tye.Hosting/Watch/DotNetWatcher.cs index b3e89dfe..42b3e1d5 100644 --- a/src/Microsoft.Tye.Hosting/Watch/DotNetWatcher.cs +++ b/src/Microsoft.Tye.Hosting/Watch/DotNetWatcher.cs @@ -88,7 +88,7 @@ namespace Microsoft.DotNet.Watcher if (finishedTask == processTask) { // Now wait for a file to change before restarting process - await fileSetWatcher.GetChangedFileAsync(cancellationToken, () => _logger.LogWarning("Waiting for a file to change before restarting dotnet...")); + await fileSetWatcher.GetChangedFileAsync(cancellationToken, () => _logger.LogWarning("watch: {Replica} Waiting for a file to change before restarting dotnet...", replica)); } if (!string.IsNullOrEmpty(fileSetTask.Result)) @@ -112,7 +112,8 @@ namespace Microsoft.DotNet.Watcher // Build failed, keep retrying builds until successful build. } - await fileSetWatcher.GetChangedFileAsync(cancellationToken, () => _logger.LogWarning("Waiting for a file to change before restarting dotnet...")); + // Now wait for a file to change before restarting process + await fileSetWatcher.GetChangedFileAsync(cancellationToken, () => _logger.LogWarning("watch: {Replica} Waiting for a file to change before restarting dotnet...", replica)); } } }